blob: 3f0b6e379eaa9416f4e76ed508b3269e86d974af [file] [log] [blame]
/*
* 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.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
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.WXPerformance;
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.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;
/**
* 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 static int reInitCount = 1;
private static String crashUrl = null;
private static long lastCrashTime = 0;
/**
* 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;
/**
* Whether JS Framework(main.js) has been initialized.
*/
private boolean mInit = 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;
}
private boolean isJSFrameworkInit() {
return mInit;
}
private void initWXBridge(boolean remoteDebug) {
if (remoteDebug && WXEnvironment.isApkDebugable()) {
WXEnvironment.sDebugServerConnectable = true;
}
if (mWxDebugProxy != null) {
mWxDebugProxy.stop(false);
}
if (WXEnvironment.sDebugServerConnectable && WXEnvironment.isApkDebugable()) {
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() {
mInit = 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) {
WXLogUtils.e("[WXBridgeManager] callNative exception: ", e);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, "[WXBridgeManager] callNativeModule exception " + e.getCause());
}
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);
return dom.callDomMethod(method, arguments);
} else {
return callModuleMethod(instanceId, module,
method, arguments, options);
}
} catch (Exception e) {
WXLogUtils.e("[WXBridgeManager] callNative exception: ", e);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, "[WXBridgeManager] callNativeModule exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, "[WXBridgeManager] callNativeModule exception " + e.getCause());
}
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)) {
WXLogUtils.e("[WXBridgeManager] callNative: call Native tasks is null");
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, "[WXBridgeManager] callNative: call Native tasks is 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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, "[WXBridgeManager] callNative exception " + e.getCause());
}
}
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");
// }
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_CREATEBODY, "[WXBridgeManager] callCreateBody: call CreateBody tasks is 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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_CREATEBODY, "[WXBridgeManager] callCreateBody exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, "[WXBridgeManager] callUpdateFinish exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERROR_DOM_CREATEFINISH, "[WXBridgeManager] callCreateFinish exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERROR_DOM_REFRESHFINISH, "[WXBridgeManager] callRefreshFinish exception " + e.getCause());
}
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");
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_UPDATEATTRS, "[WXBridgeManager] callUpdateAttrs: call UpdateAttrs tasks is 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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_UPDATEATTRS, "[WXBridgeManager] callUpdateAttrs exception " + e.getCause());
}
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");
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_UPDATESTYLE, "[WXBridgeManager] callUpdateStyle: call UpdateStyle tasks is 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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_UPDATESTYLE, "[WXBridgeManager] callUpdateStyle exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_REMOVEELEMENT, "[WXBridgeManager] callRemoveElement exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_MOVEELEMENT, "[WXBridgeManager] callMoveElement exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_ADDEVENT, "[WXBridgeManager] callAddEvent exception " + e.getCause());
}
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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_DOM_REMOVEEVENT, "[WXBridgeManager] callRemoveEvent exception " + e.getCause());
}
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
mInit = 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);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_RELOAD_PAGE, "[WXBridgeManager] callReloadPage exception " + e.getCause());
}
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();
}
// Log.e("reportServerCrash", "WXBridge reportServerCrash crashFile:" + origin_filename);
// String filename = CRASHPATH;
// File oldfile = new File(origin_filename);
// File newfile = new File(filename);
// if (newfile.exists() && newfile.isDirectory()) {
// Date date = new Date();
// DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
// String time = format.format(date);
//
// filename += "/native" + time + "_bg_jni.log";
// newfile = new File(filename);
// Log.e("reportServerCrash", "WXBridge reportServerCrash time:" + time + " filename" + filename);
// if (oldfile.exists()) {
// oldfile.renameTo(newfile);
// try {
// FileOutputStream fos = new FileOutputStream (new File(filename), true) ;
// String str = "log end: " + time + "\n";
// fos.write(str.getBytes()) ;
// fos.close ();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// } else {
// Log.e("reportServerCrash", "WXBridge /data/data/com.taobao.taobao/app_tombstone/com.taobao.taobao/crashsdk/logs not exsist");
// }
} 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.WX_CREATE_INSTANCE_ERROR,
"createInstance failed!");
}
String err = "[WXBridgeManager] invokeRefreshInstance: framework.js uninitialized.";
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, err);
WXLogUtils.d(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 " + e.getCause();
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, err);
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.WX_CREATE_INSTANCE_ERROR, "createInstance fail!");
return;
}
if (!isJSFrameworkInit() && reInitCount == 1) {
instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR, "createInstance fail!");
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()) {
instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR, "createInstance "
+ "fail!");
String err = "[WXBridgeManager] invokeCreateInstance: framework.js uninitialized.";
commitJSBridgeAlarmMonitor(instance.getInstanceId(), WXErrorCode.WX_ERR_INVOKE_NATIVE, err);
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};
invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
} catch (Throwable e) {
instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR,
"createInstance failed!");
String err = "[WXBridgeManager] invokeCreateInstance " + e.getCause()
+ " template md5 " + WXFileUtils.md5(template) + " length " + (template == null ? 0 : template.length());
commitJSBridgeAlarmMonitor(instance.getInstanceId(), WXErrorCode.WX_ERR_INVOKE_NATIVE, 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};
invokeExecJS(instanceId, null, METHOD_DESTROY_INSTANCE, args);
} catch (Throwable e) {
String err = "[WXBridgeManager] invokeDestroyInstance " + e.getCause();
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE, err);
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)) {
mInit = false;
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_FRAMEWORK, "JS Framework is empty!");
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);
mInit = true;
if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkReady();
}
execRegisterFailTask();
WXEnvironment.JsFrameworkInit = true;
registerDomModule();
String reinitInfo = "";
if (reInitCount > 1) {
reinitInfo = "reinit Framework:";
}
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_SUCCESS, reinitInfo + "success");
} else {
if (reInitCount > 1) {
WXLogUtils.e("[WXBridgeManager] invokeReInitFramework ExecuteJavaScript fail");
String err = "[WXBridgeManager] invokeReInitFramework ExecuteJavaScript fail reinit FrameWork";
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_REINIT_FRAMEWORK, err);
} else {
WXLogUtils.e("[WXBridgeManager] invokeInitFramework ExecuteJavaScript fail");
String err = "[WXBridgeManager] invokeInitFramework ExecuteJavaScript fail";
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_FRAMEWORK, err);
}
}
} catch (Throwable e) {
if (reInitCount > 1) {
WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
String err = "[WXBridgeManager] invokeInitFramework reinit FrameWork exception!#" + e.toString();
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_REINIT_FRAMEWORK, err);
} else {
WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
String err = "[WXBridgeManager] invokeInitFramework exception!#" + e.toString();
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_FRAMEWORK, err);
}
}
}
}
@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#" + e.toString();
commitJSBridgeAlarmMonitor(message.obj.toString(), WXErrorCode.WX_ERR_JS_EXECUTE, err);
}
// 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);
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_EXECUTE, "invokeRegisterService");
}
}
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("[WXBridgeManager] 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) {
WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", e);
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_EXECUTE, "invokeRegisterModules");
}
}
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);
commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_EXECUTE, "invokeRegisterComponents");
}
}
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) {
instance.onJSException(WXErrorCode.WX_ERR_JS_EXECUTE.getErrorCode(), function, exception);
if (METHOD_CREATE_INSTANCE.equals(function)) {
try {
if (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;
}
} catch (Exception e) {
e.printStackTrace();
}
}
String err = "function:" + function + "#exception:" + exception;
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_JS_EXECUTE, err);
}
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);
if (WXEnvironment.isApkDebugable()) {
WXLogUtils.d(jsException.toString());
}
}
}
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;
}
}