diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java index d66b4445ce..5d78e195bd 100644 --- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java +++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java @@ -95,6 +95,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.PriorityQueue; @@ -152,6 +153,7 @@ public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChan private Map mContainerInfo; public boolean isNewFsEnd = false; + private List componentsInfoExceedGPULimit = new LinkedList<>(); /** * bundle type @@ -206,6 +208,13 @@ public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChan * */ private boolean mAutoAdjustDeviceWidth = WXEnvironment.AUTO_ADJUST_ENV_DEVICE_WIDTH; + public List getComponentsExceedGPULimit(){return componentsInfoExceedGPULimit;} + @RestrictTo(Scope.LIBRARY) + public void setComponentsInfoExceedGPULimit(JSONObject component){ + if(component!= null && !component.isEmpty()){ + componentsInfoExceedGPULimit.add(component); + } + } public List getLayerOverFlowListeners() { return mLayerOverFlowListeners; @@ -827,7 +836,7 @@ private void renderInternal(String pageName, mWXPerformance.JSTemplateSize = template.length() / 1024f; mApmForInstance.addStats(WXInstanceApm.KEY_PAGE_STATS_BUNDLE_SIZE,mWXPerformance.JSTemplateSize); mRenderStartTime = System.currentTimeMillis(); - WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName);; + WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName); if(mAutoAdjustDeviceWidth && WXDeviceUtils.isAutoResize(mContext)){ if(WXEnvironment.AUTO_UPDATE_APPLICATION_SCREEN_SIZE) { WXViewUtils.updateApplicationScreen(mContext); diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java index 8968596338..87f755760c 100644 --- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java +++ b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java @@ -62,6 +62,7 @@ import com.taobao.weex.performance.WXInstanceApm; import com.taobao.weex.performance.WXStateRecord; import com.taobao.weex.ui.WXComponentRegistry; +import com.taobao.weex.ui.WXRenderManager; import com.taobao.weex.ui.action.ActionReloadPage; import com.taobao.weex.ui.action.BasicGraphicAction; import com.taobao.weex.ui.action.GraphicActionAddElement; @@ -102,11 +103,13 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Stack; import java.util.concurrent.CountDownLatch; @@ -851,7 +854,7 @@ public int callReportCrashReloadPage(String instanceId, String crashFile) { Log.d("jsengine", "callReportCrashReloadPage crashFile:" + crashFile); } } catch (Throwable e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } WXStateRecord.getInstance().onJSCCrash(); callReportCrash(crashFile, instanceId, url); @@ -955,7 +958,7 @@ public void run() { commitJscCrashAlarmMonitor(IWXUserTrackAdapter.JS_BRIDGE, WXErrorCode.WX_ERR_JSC_CRASH, result.toString(), instanceId, url); br.close(); } catch (Exception e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } } else { WXLogUtils.e("[WXBridgeManager] callReportCrash crash file is empty"); @@ -1536,7 +1539,7 @@ private void invokeCreateInstance(@NonNull WXSDKInstance instance, Script templa WXLogUtils.e("end getBundleType type:" + type.toString() + " time:" + (end - start)); } } catch (Throwable e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } try { @@ -1566,7 +1569,7 @@ private void invokeCreateInstance(@NonNull WXSDKInstance instance, Script templa options.put("env", mInitParams.toMap()); } } catch (Throwable e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } instance.bundleType = type; if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) { @@ -1694,7 +1697,7 @@ public WXJSObject optionObjConvert(boolean useSandBox, BundType type, WXJSObject } return new WXJSObject(WXJSObject.JSON, obj.toString()); } catch (Throwable e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } return opt; @@ -1748,7 +1751,7 @@ else if(RAX.equalsIgnoreCase(type)){ } return BundType.Others; } catch (Throwable e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); return BundType.Others; } } @@ -2030,7 +2033,7 @@ private void initFramework(String framework) { adapter.commit(WXEnvironment.getApplication(),"sJSFMStartListener",IWXUserTrackAdapter.COUNTER,null,params); } }catch (Exception e){ - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } } @@ -2039,7 +2042,7 @@ private void initFramework(String framework) { try { crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath(); } catch (Exception e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } boolean pieSupport = true; try { @@ -2047,7 +2050,7 @@ private void initFramework(String framework) { pieSupport = false; } } catch (Exception e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } sInitFrameWorkMsg.append(" | pieSupport:").append(pieSupport); WXLogUtils.d("[WXBridgeManager] initFrameworkEnv crashFile:" + crashFile + " pieSupport:" + pieSupport); @@ -2443,7 +2446,7 @@ public void reportJSException(String instanceId, String function, return; } } catch (Exception e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } } if (METHOD_CREATE_INSTANCE.equals(function) && !instance.getApmForInstance().hasAddView){ @@ -2489,17 +2492,17 @@ private void doReportJSException(String instanceId, String function,WXErrorCode exceptionExt = result.toString(); br.close(); } catch (Exception e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } } file.delete(); } } catch (Throwable throwable) { - throwable.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(throwable)); } } } catch (Throwable e) { - e.printStackTrace(); + WXLogUtils.e(WXLogUtils.getStackTrace(e)); } exception += "\n" + exceptionExt; WXLogUtils.e("reportJSException:" + exception); @@ -2948,7 +2951,69 @@ public int callUpdateAttrs(String instanceId, String ref, HashMap 0 && (layoutSize.getHeight() > limit || layoutSize.getWidth() > limit)){ + Map ext = new ArrayMap<>(); + WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instanceId,ref); + ext.put("GPU limit",String.valueOf(limit)); + ext.put("component.width",String.valueOf(layoutSize.getWidth())); + ext.put("component.height",String.valueOf(layoutSize.getHeight())); + if (component.getComponentType() != null && !component.getComponentType().isEmpty()) { + ext.put("component.type", component.getComponentType()); + } + if (component.getStyles() != null && !component.getStyles().isEmpty()) { + ext.put("component.style", component.getStyles().toString()); + } + if (component.getAttrs() != null && !component.getAttrs().isEmpty()) { + ext.put("component.attr", component.getAttrs().toString()); + } + if (component.getEvents() != null && !component.getEvents().isEmpty()) { + ext.put("component.event", component.getEvents().toString()); + } + if (component.getMargin() != null) { + ext.put("component.margin", component.getMargin().toString()); + } + if (component.getPadding() != null) { + ext.put("component.padding", component.getPadding().toString()); + } + if (component.getBorder() != null) { + ext.put("component.border", component.getBorder().toString()); + } + JSONObject map = new JSONObject(); + map.putAll(ext); + WXSDKManager.getInstance().getSDKInstance(instanceId).setComponentsInfoExceedGPULimit(map); + if(shouldReportGPULimit()) { + WXExceptionUtils.commitCriticalExceptionRT(instanceId + , WXErrorCode.WX_RENDER_WAR_GPU_LIMIT_LAYOUT, + "WXBridgeManager", + String.format(Locale.ENGLISH, "You are creating a component(%s x %2$s) which exceeds the limit of gpu(%3$s x %3$s),it may cause crash", + String.valueOf(layoutSize.getWidth()), String.valueOf(layoutSize.getHeight()), String.valueOf(limit)), + ext); + } + } + } public int callLayout(String pageId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index) { if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(ref)) { @@ -2982,6 +3047,7 @@ public int callLayout(String pageId, String ref, int top, int bottom, int left, if (instance != null) { GraphicSize size = new GraphicSize(width, height); GraphicPosition position = new GraphicPosition(left, top, right, bottom); + reportIfReachGPULimit(pageId,ref,size); GraphicActionAddElement addAction = instance.getInActiveAddElementAction(ref); if(addAction!=null) { addAction.setRTL(isRTL); diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java b/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java index 0556879074..df09117409 100644 --- a/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java @@ -223,6 +223,7 @@ public enum WXErrorCode { WX_RENDER_ERR_INSTANCE_ID_NULL("-9618", "WX_RENDER_ERR_INSTANCE_ID_NULL", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE), WX_RENDER_ERR_LIST_INVALID_COLUMN_COUNT("-9619", "WX_RENDER_ERR_LIST_INVALID_COLUMNJ_CONUNT", ErrorType.JS_ERROR, ErrorGroup.JS), WX_RENDER_ERR_TEXTURE_SETBACKGROUND("-9620", "WX_RENDER_ERR_TEXTURE_SETBACKGROUND", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE), + WX_RENDER_WAR_GPU_LIMIT_LAYOUT("-9621", "WX_RENDER_WAR_GPU_LIMIT_LAYOUT", ErrorType.JS_ERROR,ErrorGroup.JS), WX_KEY_EXCEPTION_NO_BUNDLE_TYPE("-9801", "Fatal Error : No bundle type in js bundle head, cause white screen or memory leak!!", ErrorType.JS_ERROR, ErrorGroup.JS), /** diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java index 928c4915ba..85f54b7202 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java @@ -18,6 +18,7 @@ */ package com.taobao.weex.ui; +import android.opengl.GLES10; import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; @@ -33,6 +34,7 @@ import com.taobao.weex.ui.action.GraphicActionBatchAction; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.utils.WXExceptionUtils; +import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXUtils; import java.util.ArrayList; @@ -41,6 +43,14 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + + + /** * Manager class for render operation, mainly for managing {@link RenderContextImpl}. * This is not a thread-safe class @@ -54,6 +64,7 @@ public class WXRenderManager { private final int MAX_DROP_FRAME_NATIVE_BATCH = 2000; private final static String sKeyAction = "Action"; private static int nativeBatchTimes = 0; + private static int mOpenGLRenderLimitValue = 0; public WXRenderManager() { mRenderContext = new ConcurrentHashMap<>(); @@ -81,6 +92,56 @@ public WXSDKInstance getWXSDKInstance(String instanceId) { return statement.getWXSDKInstance(); } + public static int getOpenGLRenderLimitValue() { + if(mOpenGLRenderLimitValue == 0){ + int maxsize = 0; + try { + EGL10 egl = (EGL10) EGLContext.getEGL(); + EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + int[] vers = new int[2]; + egl.eglInitialize(dpy, vers); + int[] configAttr = { + EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER, + EGL10.EGL_LEVEL, 0, + EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, + EGL10.EGL_NONE}; + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfig = new int[1]; + egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig); + if(numConfig[0] == 0){ + //There is something wrong with opengl environment. + maxsize = -1; + egl.eglTerminate(dpy); + }else { + EGLConfig config = configs[0]; + int[] surfAttr = { + EGL10.EGL_WIDTH, 64, + EGL10.EGL_HEIGHT, 64, + EGL10.EGL_NONE}; + EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr); + final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;// missing in EGL10 + int[] ctxAttrib = { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL10.EGL_NONE}; + EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib); + egl.eglMakeCurrent(dpy, surf, surf, ctx); + int[] maxSize = new int[1]; + GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); + egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_CONTEXT); + egl.eglDestroySurface(dpy, surf); + egl.eglDestroyContext(dpy, ctx); + egl.eglTerminate(dpy); + maxsize = maxSize[0]; + } + } catch(Exception e){ + WXLogUtils.e(WXLogUtils.getStackTrace(e)); + } + mOpenGLRenderLimitValue = maxsize; + } + return mOpenGLRenderLimitValue; + } + @RestrictTo(Scope.LIBRARY) public void postOnUiThread(Runnable runnable, long delayMillis) { mWXRenderHandler.postDelayed(WXThread.secure(runnable), delayMillis); diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java index ca1b6ecf44..fa00470081 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java @@ -60,6 +60,7 @@ import com.taobao.weex.WXSDKInstance; import com.taobao.weex.WXSDKManager; import com.taobao.weex.adapter.IWXAccessibilityRoleAdapter; +import com.taobao.weex.adapter.IWXConfigAdapter; import com.taobao.weex.bridge.EventResult; import com.taobao.weex.bridge.Invoker; import com.taobao.weex.bridge.WXBridgeManager; @@ -78,6 +79,7 @@ import com.taobao.weex.tracing.Stopwatch; import com.taobao.weex.tracing.WXTracing; import com.taobao.weex.ui.IFComponentHolder; +import com.taobao.weex.ui.WXRenderManager; import com.taobao.weex.ui.action.BasicComponentData; import com.taobao.weex.ui.action.GraphicActionAnimation; import com.taobao.weex.ui.action.GraphicActionUpdateStyle; @@ -1682,12 +1684,33 @@ public void setBackgroundImage(@NonNull String bgImage) { getOrCreateBorder().setImage(shader); } } + private boolean shouldCancelHardwareAccelerate() { + IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter(); + boolean cancel_hardware_accelerate = false; + if (adapter != null) { + try { + cancel_hardware_accelerate = Boolean.parseBoolean(adapter + .getConfig("android_weex_test_gpu", + "cancel_hardware_accelerate", + "false")); + }catch (Exception e){ + WXLogUtils.e(WXLogUtils.getStackTrace(e)); + } + WXLogUtils.i("cancel_hardware_accelerate : " + cancel_hardware_accelerate); + } + return cancel_hardware_accelerate; + } public void setOpacity(float opacity) { if (opacity >= 0 && opacity <= 1 && mHost.getAlpha() != opacity) { + int limit = WXRenderManager.getOpenGLRenderLimitValue(); if (isLayerTypeEnabled()) { mHost.setLayerType(View.LAYER_TYPE_HARDWARE, null); } + if(isLayerTypeEnabled() && shouldCancelHardwareAccelerate() && limit > 0 && (getLayoutHeight() > limit || + getLayoutWidth() > limit)){ + mHost.setLayerType(View.LAYER_TYPE_NONE,null); + } mHost.setAlpha(opacity); } }