| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.weex.performance; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentLinkedQueue; |
| |
| import android.support.annotation.NonNull; |
| import org.apache.weex.WXSDKManager; |
| import org.apache.weex.adapter.IWXConfigAdapter; |
| import org.apache.weex.bridge.WXBridgeManager; |
| import org.apache.weex.utils.WXUtils; |
| |
| /** |
| * @author zhongcang |
| * @date 2019/6/19 |
| */ |
| public class WXStateRecord { |
| |
| private RecordList<Info> mExceptionHistory; |
| private RecordList<Info> mActionHistory; |
| private RecordList<Info> mJsfmInitHistory; |
| private RecordList<Info> mJscCrashHistory; |
| private RecordList<Info> mJscReloadHistory; |
| private RecordList<Info> mJsThradWatchHistory; |
| private RecordList<Info> mIPCExceptionHistory; |
| |
| private static class SingleTonHolder { |
| private static final WXStateRecord S_INSTANCE = new WXStateRecord(); |
| } |
| |
| public static WXStateRecord getInstance() { |
| return SingleTonHolder.S_INSTANCE; |
| } |
| |
| private WXStateRecord() { |
| mExceptionHistory = new RecordList<>(10); |
| mActionHistory = new RecordList<>(20); |
| mJsfmInitHistory = new RecordList<>(10); |
| mJscCrashHistory = new RecordList<>(10); |
| mJscReloadHistory = new RecordList<>(10); |
| mJsThradWatchHistory = new RecordList<>(20); |
| mIPCExceptionHistory = new RecordList<>(20); |
| } |
| |
| /** |
| * check history exception (may be cause ws) |
| */ |
| public void recordException(String instanceId, String exception) { |
| String shortException = exception.length() > 200 ?exception.substring(0,200) : exception; |
| recordCommon(mExceptionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, shortException)); |
| } |
| |
| /** |
| * check history action (may be occupy cpu by preInstance or some task) |
| */ |
| public void recordAction(String instanceId, String action) { |
| recordCommon(mActionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, action)); |
| } |
| |
| public void recordIPCException (String instanceId,String exception){ |
| String shortException = exception.length() > 200 ?exception.substring(0,200) : exception; |
| recordCommon(mIPCExceptionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, shortException)); |
| } |
| |
| /** |
| * check onJSFMInit time,and we know when jsfm is init sucess in reloadJsEngine case |
| */ |
| public void onJSFMInit() { |
| recoreJsfmInitHistory("setJsfmVersion"); |
| } |
| |
| public void recoreJsfmInitHistory(String msg){ |
| recordCommon(mJsfmInitHistory,new Info(WXUtils.getFixUnixTime(), "JSFM", msg)); |
| } |
| |
| public void recordJsThreadWatch(String msg){ |
| recordCommon(mJsThradWatchHistory,new Info(WXUtils.getFixUnixTime(), "jsWatch", msg)); |
| } |
| |
| /** |
| * check onJSEngineReload time,and we know how many times reload and each reload time |
| */ |
| public void onJSEngineReload(String instanceId) { |
| recordCommon(mJscReloadHistory,new Info(WXUtils.getFixUnixTime(), instanceId, "onJSEngineReload")); |
| } |
| |
| /** |
| * check jsc crash time,and we know how many times jscCrash and each crash time |
| */ |
| public void onJSCCrash(String instanceId) { |
| recordCommon(mJscCrashHistory,new Info(WXUtils.getFixUnixTime(), instanceId, "onJSCCrash")); |
| } |
| |
| private void recordCommon(RecordList<Info> list ,Info info){ |
| if (null == list || null == info){ |
| return; |
| } |
| try { |
| list.add(info); |
| if (!list.isEmpty() && list.size()>list.maxSize){ |
| list.poll(); |
| } |
| }catch (Throwable e){ |
| e.getStackTrace(); |
| } |
| } |
| |
| public Map<String, String> getStateInfo() { |
| Map<String, String> stateInfo = new HashMap<>(5); |
| stateInfo.put("reInitCount", String.valueOf(WXBridgeManager.reInitCount)); |
| |
| int size = mExceptionHistory.size()+mActionHistory.size()+mJsfmInitHistory.size() |
| +mJscCrashHistory.size()+mJscReloadHistory.size()+mJsThradWatchHistory.size(); |
| |
| List<Info> reportTimeLineInfo = new ArrayList<>(size); |
| reportTimeLineInfo.addAll(mExceptionHistory); |
| reportTimeLineInfo.addAll(mActionHistory); |
| reportTimeLineInfo.addAll(mJsfmInitHistory); |
| reportTimeLineInfo.addAll(mJscCrashHistory); |
| reportTimeLineInfo.addAll(mJscReloadHistory); |
| reportTimeLineInfo.addAll(mJsThradWatchHistory); |
| reportTimeLineInfo.addAll(mIPCExceptionHistory); |
| Collections.sort(reportTimeLineInfo); |
| stateInfo.put("stateInfoList",reportTimeLineInfo.toString()); |
| |
| IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter(); |
| if (null != adapter && "true".equalsIgnoreCase(adapter.getConfig("wxapm","dumpIpcPageInfo","true"))){ |
| stateInfo.put("pageQueueInfo",WXBridgeManager.getInstance().dumpIpcPageInfo()); |
| } |
| return stateInfo; |
| } |
| |
| private static class RecordList<E> extends ConcurrentLinkedQueue<E> { |
| private int maxSize; |
| |
| public RecordList(int maxSize) { |
| super(); |
| this.maxSize = maxSize; |
| } |
| } |
| |
| private static class Info implements Comparable<Info>{ |
| private long time; |
| private String instanceId; |
| private String msg; |
| |
| public Info(long time, String instance, String msg) { |
| this.time = time; |
| this.instanceId = instance; |
| this.msg = msg; |
| } |
| |
| @Override |
| public String toString() { |
| return new StringBuilder() |
| .append('[').append(instanceId).append(',').append(time).append(',').append(msg).append("]->") |
| .toString(); |
| } |
| |
| @Override |
| public int compareTo(@NonNull Info next) { |
| if (this.time == next.time){ |
| return 0; |
| } |
| return this.time > next.time? 1:-1; |
| } |
| } |
| |
| public void startJSThreadWatchDog(){ |
| WXBridgeManager.getInstance().post(jsThreadWatchTask); |
| } |
| |
| private long jsThreadTime =-1; |
| |
| private Runnable jsThreadWatchTask = new Runnable() { |
| @Override |
| public void run() { |
| if (jsThreadTime == -1){ |
| jsThreadTime = WXUtils.getFixUnixTime(); |
| } |
| long diff = WXUtils.getFixUnixTime() - jsThreadTime; |
| recordJsThreadWatch("diff:"+diff); |
| jsThreadTime = WXUtils.getFixUnixTime(); |
| WXBridgeManager.getInstance().postDelay(jsThreadWatchTask,500); |
| } |
| }; |
| } |