throwableStacktrace;
22 |
23 | public CrashInfo() {
24 | }
25 |
26 | public CrashInfo(long timestampMillis, Thread thread, Throwable throwable) {
27 | this.timestampMillis = timestampMillis;
28 | this.threadName = thread.getName();
29 | this.threadState = String.valueOf(thread.getState());
30 | if (thread.getThreadGroup() != null) {
31 | this.threadGroupName = String.valueOf(thread.getThreadGroup().getName());
32 | }
33 | this.threadIsDaemon = thread.isDaemon();
34 | this.threadIsAlive = thread.isAlive();
35 | this.threadIsInterrupted = thread.isInterrupted();
36 | this.throwableMessage = throwable.getLocalizedMessage();
37 | this.throwableStacktrace = StacktraceUtil.getStack(throwable.getStackTrace());
38 | }
39 |
40 | @Override
41 | public String toString() {
42 | return "CrashInfo{" +
43 | "timestampMillis=" + timestampMillis +
44 | ", threadName='" + threadName + '\'' +
45 | ", threadState='" + threadState + '\'' +
46 | ", threadGroupName='" + threadGroupName + '\'' +
47 | ", threadIsDaemon=" + threadIsDaemon +
48 | ", threadIsAlive=" + threadIsAlive +
49 | ", threadIsInterrupted=" + threadIsInterrupted +
50 | ", throwableMessage='" + throwableMessage + '\'' +
51 | ", throwableStacktrace=" + throwableStacktrace +
52 | '}';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/crash/CrashMonitor.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.crash;
2 |
3 | import android.content.Context;
4 |
5 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
6 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor;
7 | import com.qiudaoyu.monitor.MonitorData;
8 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
9 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor;
10 | import com.qiudaoyu.monitor.utils.ProcessUtils;
11 |
12 | /**
13 | * 创建时间: 2018/12/11
14 | * 类描述:
15 | *
16 | * @author 秋刀鱼
17 | * @version 1.0
18 | */
19 | public class CrashMonitor extends MetricMonitor implements Thread.UncaughtExceptionHandler {
20 | private Thread.UncaughtExceptionHandler mDefaultHandler;
21 |
22 | public CrashMonitor(MetricListener metricListener) {
23 | super(metricListener);
24 | }
25 |
26 | public void start(Context context) {
27 | mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
28 | Thread.setDefaultUncaughtExceptionHandler(this);
29 | }
30 |
31 | public void stop(Context context) {
32 | Thread.setDefaultUncaughtExceptionHandler(mDefaultHandler);
33 | }
34 |
35 | @Override
36 | public void uncaughtException(Thread t, Throwable e) {
37 | metricData(MonitorData.TYPE_METRIC_CRASH, new CrashInfo(System.currentTimeMillis(), t, e));
38 |
39 | if (mDefaultHandler != null) {
40 | try {
41 | Thread.sleep(3000);
42 | } catch (InterruptedException e1) {
43 | }
44 | mDefaultHandler.uncaughtException(t, e);
45 | } else {
46 | ProcessUtils.killProcessAndExit();
47 | }
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/MemMonitor.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory;
2 |
3 | import android.content.Context;
4 |
5 | import com.qiudaoyu.monitor.analysis.memory.data.Memory;
6 | import com.qiudaoyu.monitor.analysis.memory.gc.GcInfo;
7 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
8 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor;
9 | import com.qiudaoyu.monitor.MonitorData;
10 | import com.qiudaoyu.monitor.analysis.memory.data.Memory;
11 | import com.qiudaoyu.monitor.analysis.memory.gc.Gc;
12 | import com.qiudaoyu.monitor.analysis.memory.gc.GcInfo;
13 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
14 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor;
15 | import com.qiudaoyu.monitor.log.MLog;
16 | import com.qiudaoyu.monitor.utils.ContentLisenter;
17 | import com.qiudaoyu.monitor.utils.DeviceUtils;
18 | import com.qiudaoyu.monitor.utils.ShellUtils;
19 |
20 | /**
21 | * 创建时间: 2018/12/11
22 | * 类描述:
23 | *
24 | * @author 秋刀鱼
25 | * @version 1.0
26 | */
27 | public class MemMonitor extends MetricMonitor {
28 |
29 | private Thread workDamondThread;
30 |
31 | private Thread workGcDamondThread;
32 |
33 | public MemMonitor(MetricListener metricListener) {
34 | super(metricListener);
35 | }
36 |
37 | @Override
38 | public void start(final Context context) {
39 | if (isInstalled(MonitorData.TYPE_METRIC_MEM)) {
40 | workDamondThread = new Thread(new Runnable() {
41 | @Override
42 | public void run() {
43 | synchronized (workDamondThread) {
44 | while (!Thread.interrupted()) {
45 | synchronized (workDamondThread) {
46 | try {
47 | workDamondThread.wait(1000);
48 | } catch (InterruptedException e) {
49 | }
50 | }
51 |
52 | //收集mem数据
53 | metricData(MonitorData.TYPE_METRIC_MEM, Memory.getAppMemInfo(context));
54 | }
55 | }
56 | }
57 | });
58 | workDamondThread.start();
59 | }
60 | if (isInstalled(MonitorData.TYPE_METRIC_GC)) {
61 | workGcDamondThread = new Thread(new Runnable() {
62 | @Override
63 | public void run() {
64 | synchronized (workGcDamondThread) {
65 | while (!Thread.interrupted()) {
66 | synchronized (workGcDamondThread) {
67 | try {
68 | workGcDamondThread.wait(1000);
69 | } catch (InterruptedException e) {
70 | }
71 | }
72 | //收集Gc数据
73 | ShellUtils.execCommand(new String[]{"logcat", "-v", "time"}, false, new ContentLisenter() {
74 | @Override
75 | public void content(String content) {
76 | if (content.contains("GC")
77 | && content.contains("paused")
78 | && content.contains("freed")
79 | && content.contains(String.valueOf(android.os.Process.myPid()))
80 | && !content.contains(MLog.customTagPrefix)
81 | && !content.contains("gcString")
82 | && !content.contains("isArt")) {
83 | metricData(MonitorData.TYPE_METRIC_GC, new GcInfo(DeviceUtils.getIsArtInUse(), content.replace("\\", "")));
84 | }
85 | }
86 |
87 | @Override
88 | public void error(Exception e, String s) {
89 | if (e != null) {
90 | MLog.d("GC", "error", e);
91 | } else {
92 | MLog.d("GC", "error " + s);
93 | }
94 | }
95 | });
96 |
97 |
98 | }
99 | }
100 | }
101 | });
102 | workGcDamondThread.start();
103 | }
104 |
105 | }
106 |
107 | @Override
108 | public void notifyWork() {
109 | if (workDamondThread != null) {
110 | synchronized (workDamondThread) {
111 | workDamondThread.notify();
112 | }
113 | }
114 |
115 | if (workGcDamondThread != null) {
116 | synchronized (workGcDamondThread) {
117 | workGcDamondThread.notify();
118 | }
119 | }
120 | }
121 |
122 | @Override
123 | public void stop(Context context) {
124 | if (workDamondThread != null) {
125 | synchronized (workDamondThread) {
126 | workDamondThread.notify();
127 | }
128 | workDamondThread.interrupt();
129 | workDamondThread = null;
130 | }
131 |
132 | if (workGcDamondThread != null) {
133 | synchronized (workGcDamondThread) {
134 | workGcDamondThread.notify();
135 | }
136 | workGcDamondThread.interrupt();
137 | workGcDamondThread = null;
138 | }
139 |
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/data/HeapInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory.data;
2 |
3 | /**
4 | *
5 | */
6 | public class HeapInfo {
7 | public long freeMemKb;
8 | public long maxMemKb;
9 | public long allocatedKb;
10 |
11 | @Override
12 | public String toString() {
13 | return "HeapInfo{" +
14 | "freeMemKb=" + freeMemKb +
15 | ", maxMemKb=" + maxMemKb +
16 | ", allocatedKb=" + allocatedKb +
17 | '}';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/data/MemInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory.data;
2 |
3 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
4 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
5 |
6 | /**
7 | *
8 | */
9 | public class MemInfo extends MetricInfo {
10 |
11 | //java堆数据
12 | public long freeMemKb;
13 | public long maxMemKb;
14 | public long allocatedKb;
15 |
16 | //native
17 | public long nativeAllocatedKb;
18 |
19 | //进程总内存
20 | public long proMemKb;
21 |
22 | //可用RAM
23 | public long availMemKb;
24 | //手机总RAM
25 | public long totalMemKb;
26 | //内存占用满的阀值,超过即认为低内存运行状态,可能会Kill process
27 | public long lowMemThresholdKb;
28 | //是否低内存状态运行
29 | public boolean isLowMemory;
30 |
31 | public long time;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/data/PssInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory.data;
2 |
3 | /**
4 | *
5 | */
6 |
7 | public class PssInfo {
8 | public int totalPssKb;
9 | public int dalvikPssKb;
10 | public int nativePssKb;
11 | public int otherPssKb;
12 |
13 | @Override
14 | public String toString() {
15 | return "PssInfo{" +
16 | "totalPss=" + totalPssKb +
17 | ", dalvikPss=" + dalvikPssKb +
18 | ", nativePss=" + nativePssKb +
19 | ", otherPss=" + otherPssKb +
20 | '}';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/data/RamInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory.data;
2 |
3 | /**
4 | *
5 | */
6 | public class RamInfo {
7 | //可用RAM
8 | public long availMemKb;
9 | //手机总RAM
10 | public long totalMemKb;
11 | //内存占用满的阀值,超过即认为低内存运行状态,可能会Kill process
12 | public long lowMemThresholdKb;
13 | //是否低内存状态运行
14 | public boolean isLowMemory;
15 |
16 | @Override
17 | public String toString() {
18 | return "RamMemoryInfo{" +
19 | "availMem=" + availMemKb +
20 | ", totalMem=" + totalMemKb +
21 | ", lowMemThreshold=" + lowMemThresholdKb +
22 | ", isLowMemory=" + isLowMemory +
23 | '}';
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/gc/Gc.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory.gc;
2 |
3 | /**
4 | * 创建时间: 2018/12/4
5 | * 类描述:
6 | *
7 | * 收集logcat中的GC日志
8 | *
9 | * @author 秋刀鱼
10 | * @version 1.0
11 | */
12 | public class Gc {
13 |
14 | public static final String SHELL_COMMAND = "logcat -v time %s | grep GC";
15 | //logcat捕捉GC日志
16 | //Dalvik/Art
17 | //adb shell logcat com.zmsoft.kds | grep -e GC_ -e AllocSpace
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/gc/GcInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory.gc;
2 |
3 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
4 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
5 |
6 | /**
7 | * 创建时间: 2018/12/4
8 | * 类描述:
9 | *
10 | * 收集logcat中的GC日志
11 | *
12 | * @author 秋刀鱼
13 | * @version 1.0
14 | */
15 | public class GcInfo extends MetricInfo {
16 | //logcat捕捉GC日志
17 | //Dalvik/Art
18 | //adb shell logcat com.zmsoft.kds | grep -e GC_ -e AllocSpace
19 |
20 | boolean isArt;
21 | String gcString;
22 |
23 | public GcInfo(boolean isArt, String gcString) {
24 | this.isArt = isArt;
25 | this.gcString = gcString;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/memory/leak/LeakWrapper.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.memory.leak;
2 |
3 | /**
4 | * 创建时间: 2018/3/21
5 | * 类描述:
6 | *
7 | * 检测内存泄漏,
8 | * dump heap,
9 | * 裁剪hprof,上传服务器以便分析
10 | *
11 | * @author 秋刀鱼
12 | * @version 1.0
13 | */
14 |
15 | public class LeakWrapper {
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/metric/AbstractSampler.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.metric;
2 |
3 | import java.util.concurrent.atomic.AtomicBoolean;
4 |
5 |
6 | /**
7 | * 每隔一个时间段做一次sample操作
8 | */
9 | public abstract class AbstractSampler {
10 |
11 | private static final int DEFAULT_SAMPLE_INTERVAL = 300;
12 |
13 | protected AtomicBoolean mShouldSample = new AtomicBoolean(false);
14 |
15 | //每隔interval时间dump一次信息
16 | protected long mSampleInterval;
17 |
18 | private Runnable mRunnable = new Runnable() {
19 | @Override
20 | public void run() {
21 | doSample();
22 |
23 | if (mShouldSample.get()) {
24 | HandlerThreadFactory.getDoDumpThreadHandler()
25 | .postDelayed(mRunnable, mSampleInterval);
26 | }
27 | }
28 | };
29 | private long sampleDelay;
30 |
31 | public AbstractSampler(long sampleInterval) {
32 | if (0 == sampleInterval) {
33 | sampleInterval = DEFAULT_SAMPLE_INTERVAL;
34 | }
35 | mSampleInterval = sampleInterval;
36 | }
37 |
38 | public void start() {
39 | if (mShouldSample.get()) {
40 | return;
41 | }
42 | mShouldSample.set(true);
43 |
44 | HandlerThreadFactory.getDoDumpThreadHandler().removeCallbacks(mRunnable);
45 | HandlerThreadFactory.getDoDumpThreadHandler().postDelayed(mRunnable,
46 | getSampleDelay());
47 | }
48 |
49 | private long getSampleDelay() {
50 | return sampleDelay;
51 | }
52 |
53 | public void setSampleDelay(long sampleDelay) {
54 | this.sampleDelay = sampleDelay;
55 | }
56 |
57 | public void stop() {
58 | if (!mShouldSample.get()) {
59 | return;
60 | }
61 | mShouldSample.set(false);
62 | HandlerThreadFactory.getDoDumpThreadHandler().removeCallbacks(mRunnable);
63 | }
64 |
65 | public abstract void doSample();
66 |
67 | public void setSampleInterval(long sampleInterval) {
68 | mSampleInterval = sampleInterval;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/metric/HandlerThreadFactory.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.metric;
2 |
3 | import android.os.Handler;
4 | import android.os.HandlerThread;
5 |
6 | public final class HandlerThreadFactory {
7 |
8 | /**
9 | * dump线程
10 | */
11 | private static HandlerThreadWrapper sDoDumpThread = new HandlerThreadWrapper("do-dump");
12 | /**
13 | * 获取dump数据线程
14 | */
15 | private static HandlerThreadWrapper sObtainDumpThread = new HandlerThreadWrapper("obtain-dump");
16 |
17 | private HandlerThreadFactory() {
18 | throw new InstantiationError("can not init this class");
19 | }
20 |
21 | public static Handler getDoDumpThreadHandler() {
22 | return sDoDumpThread.getHandler();
23 | }
24 |
25 | public static Handler getObtainDumpThreadHandler() {
26 | return sObtainDumpThread.getHandler();
27 | }
28 |
29 | private static class HandlerThreadWrapper {
30 | private Handler handler = null;
31 |
32 | public HandlerThreadWrapper(String threadName) {
33 | HandlerThread handlerThread = new HandlerThread(threadName);
34 | handlerThread.start();
35 | handler = new Handler(handlerThread.getLooper());
36 | }
37 |
38 | public Handler getHandler() {
39 | return handler;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/metric/MetricInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.metric;
2 |
3 | /**
4 | * 创建时间: 2018/12/11
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public class MetricInfo {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/metric/MetricListener.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.metric;
2 |
3 | /**
4 | * 创建时间: 2018/12/11
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public interface MetricListener {
11 | void metric(int type, Object data);
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/metric/MetricMonitor.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.metric;
2 |
3 | import android.content.Context;
4 |
5 | import com.qiudaoyu.monitor.Monitor;
6 |
7 | /**
8 | * 创建时间: 2018/12/11
9 | * 类描述:
10 | *
11 | * @author 秋刀鱼
12 | * @version 1.0
13 | */
14 | public class MetricMonitor {
15 | protected MetricListener metricListener;
16 |
17 | protected volatile int sampleInterval;
18 |
19 |
20 | public MetricMonitor(MetricListener metricListener) {
21 | this.metricListener = metricListener;
22 | }
23 |
24 | public static boolean isInstalled(int type) {
25 | return Monitor.isInstalled(type);
26 | }
27 |
28 | protected void metricData(int type, Object data) {
29 | if (metricListener != null) {
30 | metricListener.metric(type, data);
31 | }
32 | }
33 |
34 | public void start(Context context) {
35 |
36 | }
37 |
38 | public void stop(Context context) {
39 |
40 | }
41 |
42 | public void setForground(boolean isForground) {
43 |
44 | }
45 |
46 |
47 | public void notifyWork() {
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/network/NetMonitor.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.network;
2 |
3 | import android.content.Context;
4 |
5 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
6 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor;
7 | import com.qiudaoyu.monitor.analysis.network.http.okhttp.NetWorkInterceptor;
8 | import com.qiudaoyu.monitor.Monitor;
9 | import com.qiudaoyu.monitor.MonitorData;
10 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
11 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor;
12 | import com.qiudaoyu.monitor.analysis.network.http.okhttp.NetWorkInterceptor;
13 |
14 | import okhttp3.OkHttpClient;
15 |
16 | /**
17 | * 创建时间: 2018/12/11
18 | * 类描述:
19 | *
20 | * @author 秋刀鱼
21 | * @version 1.0
22 | */
23 | public class NetMonitor extends MetricMonitor {
24 |
25 | public NetMonitor(MetricListener metricListener) {
26 | super(metricListener);
27 | }
28 |
29 | public static void beforeOkHttpBuild(OkHttpClient.Builder builder) {
30 | if (builder != null && isInstalled(MonitorData.TYPE_METRIC_HTTP)) {
31 | builder.addInterceptor(new NetWorkInterceptor(new MetricListener() {
32 | @Override
33 | public void metric(int type, Object data) {
34 | Monitor.metricData(MonitorData.TYPE_METRIC_HTTP, data);
35 | }
36 | }));
37 | }
38 | }
39 |
40 | public void start(Context context) {
41 |
42 | }
43 |
44 | public void stop(Context context) {
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/network/http/HttpInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.network.http;
2 |
3 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
4 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
5 |
6 | /**
7 | * 创建时间: 2018/12/5
8 | * 类描述:
9 | */
10 | public class HttpInfo extends MetricInfo {
11 |
12 | public String trackId;
13 |
14 | public long requestSize;
15 |
16 | public long responseSize;
17 |
18 | public long startTime;
19 |
20 | public long costTime;
21 | public Exception reqExcetion;
22 | public String url;
23 | /**
24 | * 请求结果
25 | */
26 | public int code;
27 | public String exceptionString;
28 | /**
29 | * 进程时间
30 | */
31 | public long fetchStart;
32 | /**
33 | * dns
34 | */
35 | public long domainLookupStart;
36 |
37 | public long domainLookupEnd;
38 | /**
39 | * connect
40 | */
41 | public long connectStart;
42 | /**
43 | * ssl connect
44 | */
45 | public long secureConnectionStart;
46 | public long secureConnectionEnd;
47 | public long connectEnd;
48 | /**
49 | * http send
50 | */
51 | public long requestStart;
52 | public long requestEnd;
53 | /**
54 | * http rec
55 | */
56 | public long responseStart;
57 |
58 | public long firstPkg;
59 |
60 | public long responseEnd;
61 |
62 |
63 | public void setException(Exception e) {
64 | reqExcetion = e;
65 | }
66 |
67 | public void setTrackId(String trackId) {
68 | this.trackId = trackId;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/network/http/HttpStats.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.network.http;
2 |
3 | /**
4 | * 创建时间: 2018/12/5
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | * http请求流程
10 | *
11 | * https://upload-images.jianshu.io/upload_images/852671-91939d53b0f3957b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/813/format/webp
12 | *
13 | * 通过AOP方式拦截对应的网络请求API实现统计
14 | *
15 | * 例如:
16 | *
17 | * AspectJ的实现
18 | * @Pointcut("target(java.net.URLConnection) && " +
19 | * "!within(retrofit.appengine.UrlFetchClient) " +
20 | * "&& !within(okio.Okio) && !within(butterknife.internal.ButterKnifeProcessor) " +
21 | * "&& !within(com.flurry.sdk.hb)" +
22 | * "&& !within(rx.internal.util.unsafe.*) " +
23 | * "&& !within(net.sf.cglib..*)" +
24 | * "&& !within(com.huawei.android..*)" +
25 | * "&& !within(com.sankuai.android.nettraffic..*)" +
26 | * "&& !within(roboguice..*)" +
27 | * "&& !within(com.alipay.sdk..*)")
28 | * protected void baseCondition() {
29 | *
30 | * }
31 | * @Pointcut("call (org.apache.http.HttpResponse org.apache.http.client.HttpClient.execute ( org.apache.http.client.methods.HttpUriRequest))"
32 | * + "&& target(org.apache.http.client.HttpClient)"
33 | * + "&& args(request)"
34 | * + "&& !within(com.sankuai.android.nettraffic.factory..*)"
35 | * + "&& baseClientCondition()"
36 | * )
37 | * void httpClientExecute(HttpUriRequest request) {
38 | *
39 | * }
40 | */
41 | public class HttpStats {
42 |
43 |
44 |
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/network/http/okhttp/NetWorkInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.network.http.okhttp;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
6 | import com.qiudaoyu.monitor.MonitorData;
7 | import com.qiudaoyu.monitor.analysis.MasData;
8 | import com.qiudaoyu.monitor.analysis.metric.MetricListener;
9 | import com.qiudaoyu.monitor.analysis.network.http.HttpInfo;
10 | import com.qiudaoyu.monitor.log.MLog;
11 |
12 | import java.io.IOException;
13 |
14 | import okhttp3.Interceptor;
15 | import okhttp3.Request;
16 | import okhttp3.RequestBody;
17 | import okhttp3.Response;
18 | import okhttp3.ResponseBody;
19 | import okio.Buffer;
20 | import okio.BufferedSource;
21 |
22 | /**
23 | * 网络拦截器
24 | */
25 | public class NetWorkInterceptor implements Interceptor {
26 |
27 | private static final String TAG = "Okhttp";
28 |
29 | private HttpInfo mOkHttpData;
30 | private MetricListener metricListener;
31 |
32 | public NetWorkInterceptor(MetricListener metricListener) {
33 | this.metricListener = metricListener;
34 | }
35 |
36 | @Override
37 | public Response intercept(Chain chain) throws IOException {
38 |
39 | long startNs = System.currentTimeMillis();
40 | mOkHttpData = new HttpInfo();
41 | mOkHttpData.startTime = startNs;
42 |
43 | String trackId = MasData.getInstance().generatTrackId();
44 | //增加trackId
45 | Request original = chain.request();
46 | Request.Builder requestBuilder = original.newBuilder();
47 | requestBuilder.addHeader("trackId", trackId);
48 | mOkHttpData.setTrackId(trackId);
49 | Request newReq = requestBuilder.build();
50 | recordRequest(newReq);
51 |
52 | //记录结果
53 | try {
54 | Response response = chain.proceed(newReq);
55 | mOkHttpData.costTime = System.currentTimeMillis() - startNs;
56 | recordResponse(response);
57 | return response;
58 | } catch (Exception e) {
59 | mOkHttpData.costTime = System.currentTimeMillis() - startNs;
60 | mOkHttpData.setException(e);
61 | MLog.e(TAG, "HTTP FAILED: " + e);
62 | throw e;
63 | } finally {
64 | if (metricListener != null) {
65 | metricListener.metric(MonitorData.TYPE_METRIC_HTTP, mOkHttpData);
66 | }
67 | }
68 | }
69 |
70 | /**
71 | * request
72 | */
73 | private void recordRequest(Request request) {
74 | if (request == null || request.url() == null || TextUtils.isEmpty(request.url().toString())) {
75 | return;
76 | }
77 |
78 | mOkHttpData.url = request.url().toString();
79 |
80 | RequestBody requestBody = request.body();
81 | if (requestBody == null) {
82 | mOkHttpData.requestSize = request.url().toString().getBytes().length;
83 | MLog.d(TAG, "okhttp request 上行数据,大小:" + mOkHttpData.requestSize);
84 | return;
85 | }
86 |
87 | long contentLength = 0;
88 | try {
89 | contentLength = requestBody.contentLength();
90 | } catch (IOException e) {
91 | e.printStackTrace();
92 | }
93 |
94 | if (contentLength > 0) {
95 | mOkHttpData.requestSize = contentLength;
96 | } else {
97 | mOkHttpData.requestSize = request.url().toString().getBytes().length;
98 | }
99 | }
100 |
101 | /**
102 | * 设置 code responseSize
103 | */
104 | private void recordResponse(Response response) {
105 | if (response == null) {
106 | return;
107 | }
108 |
109 | mOkHttpData.code = response.code();
110 |
111 | MLog.d(TAG, "okhttp chain.proceed 状态码:" + mOkHttpData.code);
112 |
113 | if (!response.isSuccessful()) {
114 | return;
115 | }
116 |
117 | ResponseBody responseBody = response.body();
118 | if (responseBody == null) {
119 | return;
120 | }
121 |
122 | long contentLength = responseBody.contentLength();
123 |
124 | if (contentLength > 0) {
125 | MLog.d(TAG, "直接通过responseBody取到contentLength:" + contentLength);
126 | } else {
127 | BufferedSource source = responseBody.source();
128 | if (source != null) {
129 | try {
130 | source.request(Long.MAX_VALUE);
131 | } catch (IOException e) {
132 | e.printStackTrace();
133 | }
134 |
135 | Buffer buffer = source.buffer();
136 | contentLength = buffer.size();
137 |
138 | MLog.d(TAG, "通过responseBody.source()才取到contentLength:" + contentLength);
139 | }
140 | }
141 |
142 | mOkHttpData.responseSize = contentLength;
143 | MLog.d(TAG, "okhttp 接收字节数:" + mOkHttpData.responseSize);
144 | }
145 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/storage/Storage.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.storage;
2 |
3 | import android.os.Environment;
4 | import android.os.StatFs;
5 |
6 | import java.io.File;
7 |
8 | /**
9 | * 创建时间: 2018/12/4
10 | * 类描述:
11 | *
12 | * @author 秋刀鱼
13 | * @version 1.0
14 | */
15 | public class Storage {
16 | public long[] getSDCardMemory() {
17 | long[] sdCardInfo = new long[2];
18 | String state = Environment.getExternalStorageState();
19 | if (Environment.MEDIA_MOUNTED.equals(state)) {
20 | File sdcardDir = Environment.getExternalStorageDirectory();
21 | StatFs sf = new StatFs(sdcardDir.getPath());
22 | long bSize = sf.getBlockSize();
23 | long bCount = sf.getBlockCount();
24 | long availBlocks = sf.getAvailableBlocks();
25 | sdCardInfo[0] = bSize * bCount;//总大小
26 | sdCardInfo[1] = bSize * availBlocks;//可用大小
27 | }
28 | return sdCardInfo;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/thread/StackSampler.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.thread;
2 |
3 |
4 | import com.qiudaoyu.monitor.analysis.metric.AbstractSampler;
5 |
6 | import java.util.LinkedHashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * 线程堆栈信息dump
11 | */
12 | public class StackSampler extends AbstractSampler {
13 |
14 | private static final int DEFAULT_MAX_ENTRY_COUNT = 10;
15 | private static final LinkedHashMap sStackMap = new LinkedHashMap<>();
16 |
17 | private int mMaxEntryCount = DEFAULT_MAX_ENTRY_COUNT;
18 | private Thread mCurrentThread;
19 |
20 | public StackSampler(Thread thread, long sampleIntervalMillis) {
21 | this(thread, DEFAULT_MAX_ENTRY_COUNT, sampleIntervalMillis);
22 | }
23 |
24 | public StackSampler(Thread thread, int maxEntryCount, long sampleIntervalMillis) {
25 | super(sampleIntervalMillis);
26 | mCurrentThread = thread;
27 | mMaxEntryCount = maxEntryCount;
28 | }
29 |
30 | /**
31 | * 获取这个时间段内dump的堆栈信息
32 | *
33 | * @param startTime
34 | * @param endTime
35 | * @return
36 | */
37 | public Map getThreadStackEntries(long startTime, long endTime) {
38 | Map result = new LinkedHashMap<>();
39 | synchronized (sStackMap) {
40 | for (Long entryTime : sStackMap.keySet()) {
41 | if (startTime < entryTime && entryTime < endTime) {
42 | result.put(entryTime, sStackMap.get(entryTime));
43 | }
44 | }
45 | }
46 | return result;
47 | }
48 |
49 |
50 | public void doSample() {
51 | synchronized (sStackMap) {
52 | if (sStackMap.size() == mMaxEntryCount && mMaxEntryCount > 0) {
53 | sStackMap.remove(sStackMap.keySet().iterator().next());
54 | }
55 | sStackMap.put(System.currentTimeMillis(), mCurrentThread.getStackTrace());
56 | }
57 | }
58 |
59 | public void clear() {
60 | if (sStackMap != null) {
61 | sStackMap.clear();
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/ui/anr/Anr.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.ui.anr;
2 |
3 | import android.os.FileObserver;
4 |
5 | import com.tencent.mmkv.MMKV;
6 | import com.qiudaoyu.monitor.log.MLog;
7 |
8 | /**
9 | * 创建时间: 2018/12/7
10 | * 类描述:
11 | *
12 | * anr文件格式,匹配出当前进程的内容
13 | *
14 | * Android系统API提供了FileObserver抽象类(Linux的INotify机制)来监听系统/sdcard中的文件或文件夹,
15 | * FileObserver类是一个用于监听文件访问、创建、修改、删除、移动等操作的监听器,基于linux的inotify。
16 | * FileObserver 是个抽象类,必须继承它才能使用。每个FileObserver对象监听一个单独的文件或者文件夹,如果监视的是一个文件夹,
17 | * 那么文件夹下所有的文件和级联子目录的改变都会触发监听的事件。
18 | * 其实不然,经过测试并不支持递归,对于监听目录的子目录中的文件改动,FileObserver 对象是无法收到事件回调的,不仅这样,
19 | * 监听目录的子目录本身的变动也收不到事件回调。原因是由 linux 的 inotify 机制本身决定的,基于 inotify 实现的 FileObserver 自然也不支持递归监听。
20 | *
21 | * @author 秋刀鱼
22 | * @version 1.0
23 | */
24 | public class Anr {
25 | public static final String ANR_DIR = "/data/anr/traces.txt";
26 | public static final long THRESHOLD = 5000;
27 | public static long lastNotifyTime;
28 |
29 | static FileObserver fileObserver = new FileObserver(ANR_DIR, FileObserver.CREATE | FileObserver.CLOSE_WRITE) {
30 | @Override
31 | public void onEvent(int event, String simplePath) {
32 | MLog.d("anr", "anr happen : event " + event + " | path " + simplePath);
33 | long time = System.currentTimeMillis();
34 | if ((time - lastNotifyTime) > THRESHOLD) {
35 | //读取anr文件,提取到当前进程可能有的Anr信息
36 | MMKV.mmkvWithID("monitor").putLong(ANR_DIR, time);
37 | }
38 | lastNotifyTime = time;
39 | }
40 | };
41 |
42 |
43 | public static void start() {
44 | fileObserver.startWatching();
45 | }
46 |
47 | public static void stop() {
48 | fileObserver.stopWatching();
49 | }
50 |
51 | public static boolean hasAnr() {
52 | return MMKV.mmkvWithID("monitor").getLong(ANR_DIR, 0) != 0;
53 | }
54 |
55 | public static void clearAnr() {
56 | MMKV.mmkvWithID("monitor").remove(ANR_DIR);
57 | }
58 |
59 | public static void save(AnrInfo info) {
60 | if (info != null) {
61 | AnrFileParser.setUploadedKey(info.getProId(), info.getTime());
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/ui/anr/AnrInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.ui.anr;
2 |
3 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
4 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
5 |
6 | /**
7 | * ANR信息类型
8 | *
9 | * @author ArgusAPM Team
10 | */
11 | public class AnrInfo extends MetricInfo {
12 |
13 | private String proName;
14 | private long time;
15 | private String anrContent;
16 | private long proId;
17 |
18 | public String getProName() {
19 | return proName;
20 | }
21 |
22 | public void setProName(String proName) {
23 | this.proName = proName;
24 | }
25 |
26 | public long getTime() {
27 | return time;
28 | }
29 |
30 | public void setTime(long time) {
31 | this.time = time;
32 | }
33 |
34 | public String getAnrContent() {
35 | return anrContent;
36 | }
37 |
38 | public void setAnrContent(String anrContent) {
39 | this.anrContent = anrContent;
40 | }
41 |
42 | public long getProId() {
43 | return proId;
44 | }
45 |
46 | public void setProId(long proId) {
47 | this.proId = proId;
48 | }
49 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/ui/blockdetector/BlockInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.ui.blockdetector;
2 |
3 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
4 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
5 | import com.qiudaoyu.monitor.utils.StacktraceUtil;
6 |
7 | import java.util.Map;
8 |
9 | /**
10 | * 卡顿数据
11 | */
12 | public class BlockInfo extends MetricInfo {
13 |
14 | /**
15 | * 卡顿所在线程消耗的时间
16 | * 如果线程消耗时间和实际时间(costTime)差不多,那么说明在这个线程上(主线程)执行某个任务太耗时
17 | * 如果线程消耗时间远小于实际时间,那么说明这个线程正在等待资源(等待资源耗时)
18 | */
19 | public long threadTimeCost;
20 |
21 | public long start;
22 |
23 | public long costTime;
24 |
25 | public boolean isLongBlock;
26 |
27 | public Map stackSamples;
28 |
29 | public BlockInfo(long start, long costTime, long threadTimeCost, boolean isLongBlock, Map stackSamples) {
30 | this.start = start;
31 | this.costTime = costTime;
32 | this.threadTimeCost = threadTimeCost;
33 | this.isLongBlock = isLongBlock;
34 | this.stackSamples = StacktraceUtil.convertToStackString(stackSamples);
35 |
36 | }
37 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/ui/fps/Fps.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.ui.fps;
2 |
3 | import android.annotation.TargetApi;
4 | import android.os.Build;
5 | import android.view.Choreographer;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 | import java.util.concurrent.BlockingQueue;
10 | import java.util.concurrent.LinkedBlockingQueue;
11 |
12 | /**
13 | * fps收集task
14 | */
15 | public class Fps {
16 |
17 | private static Choreographer.FrameCallback frameCallback;
18 | private static int count;
19 | private static long start;
20 | private static long end;
21 |
22 | private static BlockingQueue infos;
23 |
24 | public static void start() {
25 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
26 | infos = new LinkedBlockingQueue<>();
27 | frameCallback = new Choreographer.FrameCallback() {//系统绘帧回调
28 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
29 | public void doFrame(long frameTimeNanos) {
30 | if (count == 0) {
31 | start = System.currentTimeMillis();
32 | }
33 | end = System.currentTimeMillis();
34 | if (count >= 60 || (end - start) >= 1000) {
35 | //整理帧的数据
36 | addFpsInfo(new FpsInfo(start, end, count));
37 | count = 0;
38 | } else {
39 | count++;
40 | }
41 | // 开启下一个doFrame监控
42 | Choreographer.getInstance().postFrameCallback(frameCallback);
43 | }
44 |
45 |
46 | };
47 | Choreographer.getInstance().postFrameCallback(frameCallback);
48 | }
49 | }
50 |
51 | public static void stop() {
52 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
53 | Choreographer.getInstance().postFrameCallback(null);
54 | }
55 | if (infos != null) {
56 | infos.clear();
57 | infos = null;
58 | }
59 | }
60 |
61 | private static void addFpsInfo(FpsInfo fps) {
62 | if (infos != null && fps != null) {
63 | infos.offer(fps);
64 | }
65 | }
66 |
67 | public static List getFpsInfos() {
68 | if (infos == null) {
69 | return null;
70 | }
71 | List list = new ArrayList<>();
72 | infos.drainTo(list);
73 | return list;
74 | }
75 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/ui/fps/FpsInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.ui.fps;
2 |
3 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
4 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo;
5 |
6 | /**
7 | * fps收集task
8 | */
9 | public class FpsInfo extends MetricInfo {
10 |
11 | long start;
12 | long end;
13 | int count;
14 |
15 | public FpsInfo(long start, long end, int count) {
16 | this.start = start;
17 | this.end = end;
18 | this.count = count;
19 | }
20 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/analysis/utils/MasUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.analysis.utils;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | import java.text.SimpleDateFormat;
7 | import java.util.Date;
8 | import java.util.Iterator;
9 |
10 | /**
11 | * 创建时间: 2018/12/4
12 | * 类描述:
13 | *
14 | * @author 秋刀鱼
15 | * @version 1.0
16 | */
17 | public class MasUtils {
18 | private static final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
19 |
20 | /**
21 | * 合并 JSONObject
22 | *
23 | * @param source JSONObject
24 | * @param dest JSONObject
25 | * @throws JSONException Exception
26 | */
27 |
28 | public static void mergeJSONObject(final JSONObject source, JSONObject dest) {
29 | try {
30 | Iterator superPropertiesIterator = source.keys();
31 | while (superPropertiesIterator.hasNext()) {
32 | String key = superPropertiesIterator.next();
33 | Object value = source.get(key);
34 | if (value instanceof Date) {
35 | synchronized (mDateFormat) {
36 | dest.put(key, mDateFormat.format((Date) value));
37 | }
38 | } else {
39 | dest.put(key, value);
40 | }
41 | }
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/df/config/DFConfigManager.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.df.config;
2 |
3 | import android.content.Context;
4 |
5 | import com.qiudaoyu.monitor.log.dynamiclog.config.ConfigManager;
6 | import com.qiudaoyu.monitor.log.dynamiclog.config.MethodConfig;
7 | import com.qiudaoyu.monitor.log.dynamiclog.config.ConfigManager;
8 | import com.qiudaoyu.monitor.log.dynamiclog.config.MethodConfig;
9 |
10 | /**
11 | * 创建时间: 2018/9/26
12 | * 类描述:
13 | *
14 | * @author 秋刀鱼
15 | * @version 1.0
16 | */
17 | public class DFConfigManager extends ConfigManager {
18 |
19 | private DFConfigManager() {
20 |
21 | }
22 |
23 | public static DFConfigManager getInstance() {
24 | return Single.mInstance;
25 | }
26 |
27 | @Override
28 | public Object generateData(MethodConfig config, Object data) {
29 |
30 | return null;
31 | }
32 |
33 | @Override
34 | public void queryConfigs(Context context) {
35 |
36 |
37 | }
38 |
39 | public static class Single {
40 | static DFConfigManager mInstance = new DFConfigManager();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/df/upload/MUploadService.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.df.upload;
2 |
3 | import android.content.Context;
4 |
5 | import com.qiudaoyu.monitor.upload.UploadServiceInterface;
6 |
7 | /**
8 | * 创建时间: 2018/9/26
9 | * 类描述:
10 | * 上传日志类
11 | *
12 | * @author 秋刀鱼
13 | * @version 1.0
14 | */
15 |
16 | public class MUploadService implements UploadServiceInterface {
17 |
18 | private MUploadService() {
19 |
20 | }
21 |
22 | public static MUploadService getInstance() {
23 | return Single.mInstance;
24 | }
25 |
26 | @Override
27 | public void initialize(Info args) {
28 |
29 | }
30 |
31 | @Override
32 | public void sendData(Object data) {
33 |
34 | }
35 |
36 | @Override
37 | public void setForground(boolean isForgroud) {
38 |
39 | }
40 |
41 | @Override
42 | public void shutDown() {
43 |
44 | }
45 |
46 |
47 | public static class Info {
48 | public Context context;
49 | public String pkgName;
50 | public String deviceId;
51 | public String appkey;
52 | public String secret;
53 | public String appVer;
54 | public String path;
55 | public String sdkversion;
56 | public String url;
57 | public int port;
58 | public short heartBeatInterval;
59 |
60 | public Info(Context context, String deviceId, String pkgName, String appkey, String secret, String appVer, String sdkversion, String path, short heartBeatInterval
61 | , String url, int port) {
62 | this.context = context;
63 | this.pkgName = pkgName;
64 | this.deviceId = deviceId;
65 | this.appkey = appkey;
66 | this.secret = secret;
67 | this.appVer = appVer;
68 | this.path = path;
69 | this.sdkversion = sdkversion;
70 | this.heartBeatInterval = heartBeatInterval;
71 | this.url = url;
72 | this.port = port;
73 | }
74 |
75 |
76 | }
77 |
78 |
79 | private static class Single {
80 | static MUploadService mInstance = new MUploadService();
81 | }
82 |
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/annotation/IgnoreLog.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 创建时间: 2018/12/6
10 | * 类描述:
11 | *
12 | * @author 秋刀鱼
13 | * @version 1.0
14 | */
15 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
16 | @Retention(value = RetentionPolicy.RUNTIME)
17 | public @interface IgnoreLog {
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/config/ConfigManager.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.config;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * 创建时间: 2018/9/18
7 | * 类描述:
8 | *
9 | * @author 秋刀鱼
10 | * @version 1.0
11 | */
12 | public abstract class ConfigManager {
13 |
14 | /**
15 | * 不依赖前值的多读一写的场景同步
16 | */
17 | private volatile ConfigOneWayHashTable table;
18 |
19 | private int version;
20 |
21 | public ConfigManager() {
22 | table = new ConfigOneWayHashTable();
23 | }
24 |
25 | /**
26 | *
27 | * @param nHash
28 | * @param nHashA
29 | * @param nHashB
30 | * @return
31 | */
32 | public MethodConfig getConfig(int nHash, int nHashA, int nHashB) {
33 | ConfigOneWayHashTable.HaseNode node = table.Hashed(nHash, nHashA, nHashB);
34 | if (node != null && node.data != null) {
35 | MethodConfig config = (MethodConfig) node.data;
36 | return config;
37 | }
38 | return null;
39 | }
40 |
41 | public abstract Object generateData(MethodConfig config, Object data);
42 |
43 | public abstract void queryConfigs(Context context);
44 |
45 | public void setNewConfigs(int version, ConfigOneWayHashTable.HaseNode[] nodes) {
46 | this.version = version;
47 | if (table != null) {
48 | table.setHashIndexTable(nodes);
49 | }
50 | }
51 |
52 | public void shutDown() {
53 |
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/config/MethodConfig.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.config;
2 |
3 | /**
4 | * 创建时间: 2018/9/18
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public class MethodConfig {
11 |
12 | private final static int BEFORE_MASK = 0x1;
13 | private final static int AFTER_MASK = 0x2;
14 | private final static int EXCEPTION_MASK = 0x4;
15 | private int beforeExceptionAfter;
16 | private String luaString;
17 | private String eventType;
18 |
19 |
20 | public static String getLuaRootString() {
21 | return "stacks={};";
22 | }
23 |
24 | public String getLuaString() {
25 | return luaString;
26 | }
27 |
28 | public void setLuaString(String luaString) {
29 | this.luaString = luaString;
30 | }
31 |
32 |
33 | public boolean isAfter() {
34 |
35 | return (beforeExceptionAfter & AFTER_MASK) > 0;
36 | }
37 |
38 | public boolean isException() {
39 | return (beforeExceptionAfter & EXCEPTION_MASK) > 0;
40 | }
41 |
42 | public boolean isBefore() {
43 | return (beforeExceptionAfter & BEFORE_MASK) > 0;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/context/MonitorContext.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.context;
2 |
3 | import com.qiudaoyu.monitor.log.dynamiclog.pool.ObjectPool;
4 |
5 | import org.keplerproject.luajava.LuaState;
6 |
7 | import java.util.Stack;
8 |
9 | /**
10 | * 创建时间: 2018/9/25
11 | * 类描述:
12 | *
13 | * @author 秋刀鱼
14 | * @version 1.0
15 | */
16 | public class MonitorContext extends ObjectPool.RecyclableObject {
17 | private long threadId;
18 | private String threadName;
19 | private LuaState state;
20 | private boolean inited;
21 |
22 | private Stack stack;
23 |
24 | public long getThreadId() {
25 | return threadId;
26 | }
27 |
28 | public void setThreadId(long threadId) {
29 | this.threadId = threadId;
30 | }
31 |
32 | public String getThreadName() {
33 | return threadName;
34 | }
35 |
36 | public void setThreadName(String threadName) {
37 | this.threadName = threadName;
38 | }
39 |
40 | public LuaState getState() {
41 | return state;
42 | }
43 |
44 | public void setState(LuaState state) {
45 | this.state = state;
46 | if (state != null) {
47 | setInited(true);
48 | stack = new Stack();
49 | } else {
50 | setInited(false);
51 | }
52 | }
53 |
54 | public boolean isInited() {
55 | return inited;
56 | }
57 |
58 | public void setInited(boolean inited) {
59 | this.inited = inited;
60 | }
61 |
62 |
63 | public void popTop() {
64 | if (!stack.empty()) {
65 | stack.pop();
66 | }
67 | }
68 |
69 | public boolean getTopArg() {
70 | if (!stack.empty()) {
71 | return stack.firstElement().booleanValue();
72 | }
73 | return false;
74 | }
75 |
76 | public void pushTopArg(Boolean b) {
77 | stack.push(b);
78 | }
79 |
80 | public void realese() {
81 | if (state != null) {
82 | state.close();
83 | }
84 | setState(null);
85 | if (stack != null) {
86 | stack.clear();
87 | }
88 | threadName = null;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/context/MonitorContextFactory.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.context;
2 |
3 | import com.qiudaoyu.monitor.log.dynamiclog.pool.ObjectPool;
4 |
5 | /**
6 | * 创建时间: 2018/9/25
7 | * 类描述:
8 | *
9 | * @author 秋刀鱼
10 | * @version 1.0
11 | */
12 | public class MonitorContextFactory implements ObjectPool.RecyclableFactory {
13 |
14 | @Override
15 | public MonitorContext createNew() {
16 | return new MonitorContext();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/lua/LuaConstance.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.lua;
2 |
3 | /**
4 | * 创建时间: 2018/9/25
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public class LuaConstance {
11 |
12 | public static final String STACK = "stack";
13 |
14 |
15 | public static final String CALLTOPFUNC = "callTopFunc";
16 |
17 | public static final String RELEASETOP = "releaseTop";
18 |
19 | public static final String GETTOPDATA = "getTopData";
20 |
21 |
22 | public static final String INITTOP = "initTop";
23 | public static final String DATA = "data";
24 | public static final String ARGS = "args";
25 | public static final String BEFORE = "before";
26 |
27 |
28 | public static final String AFTER = "after";
29 |
30 | public static final String EXCEPTION = "exception";
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/lua/LuaRunException.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.lua;
2 |
3 | /**
4 | * 创建时间: 2018/9/25
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public class LuaRunException extends Exception {
11 | private int javaCallLua;
12 | private int luaCallStack;
13 | private Object error;
14 | private Object error2;
15 |
16 | public LuaRunException() {
17 | super();
18 | }
19 |
20 | public LuaRunException(int javaCallLua, int luaCallStack, Object error, Object error2) {
21 | super();
22 | this.javaCallLua = javaCallLua;
23 | this.luaCallStack = javaCallLua;
24 | this.error = error;
25 | this.error2 = error2;
26 | }
27 |
28 |
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/lua/TestJavaLua.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.lua;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 | import android.widget.TextView;
6 |
7 | import com.qiudaoyu.monitor.utils.AppUtils;
8 | import com.qiudaoyu.monitor.utils.AppUtils;
9 |
10 | import org.keplerproject.luajava.LuaState;
11 | import org.keplerproject.luajava.LuaStateFactory;
12 |
13 | /**
14 | * 创建时间: 2018/10/15
15 | * 类描述:
16 | *
17 | * @author 秋刀鱼
18 | * @version 1.0
19 | */
20 | public class TestJavaLua {
21 |
22 | public static void testLua(String[] args, Context context, TextView tx) {
23 | LuaState state = LuaStateFactory.newLuaState();
24 | //加载Lua 自身类库
25 | state.openLibs();
26 |
27 | String root = AppUtils.getStringContentFromAssets("root.lua", context);
28 | String test = AppUtils.getStringContentFromAssets("test.lua", context);
29 | state.LdoString(root);
30 | state.LdoString(test);
31 | state.getGlobal("callTopFunc");
32 | state.pushString("before");
33 | state.pushJavaObject(tx);
34 | state.pcall(2, 2, 0);
35 | Log.e("1", "1");
36 |
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/dynamiclog/pool/ObjectPool.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.dynamiclog.pool;
2 |
3 | import java.util.concurrent.atomic.AtomicBoolean;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | /**
7 | * 创建时间: 2018/9/21
8 | * 类描述:固定个数的对象池
9 | *
10 | * @author 秋刀鱼
11 | * @version 1.0
12 | * @param
13 | */
14 | public final class ObjectPool {
15 | public static int RESET_NUM = 1000;
16 | private T[] mTable;
17 | private AtomicInteger mOrderNumber;
18 | private RecyclableFactory factory;
19 |
20 | /**
21 | * @param inputArray 长度为2的n次方
22 | * @param factory T的工厂
23 | */
24 | public ObjectPool(T[] inputArray, RecyclableFactory factory) {
25 | mOrderNumber = new AtomicInteger(0);
26 | mTable = inputArray;
27 | if (mTable == null) {
28 | throw new NullPointerException("The input array is null.");
29 | }
30 | if (factory == null) {
31 | throw new NullPointerException("The factory is null.");
32 | }
33 | this.factory = factory;
34 | int length = inputArray.length;
35 | if ((length & length - 1) != 0) {
36 | throw new RuntimeException("The length of input array is not 2^n.");
37 | }
38 | }
39 |
40 | public void recycle(T object) {
41 | object.isIdle.set(true);
42 | }
43 |
44 | public T obtain() {
45 | return obtain(0);
46 | }
47 |
48 | private T obtain(int retryTime) {
49 | int index = mOrderNumber.getAndIncrement();
50 | if (index > RESET_NUM) {
51 | mOrderNumber.compareAndSet(index, 0);
52 | if (index > RESET_NUM * 2) {
53 | mOrderNumber.set(0);
54 | }
55 | }
56 |
57 | int num = index & (mTable.length - 1);
58 |
59 | T target = mTable[num];
60 |
61 | if (target.isIdle.compareAndSet(true, false)) {
62 | return target;
63 | } else {
64 | //尝试3次不成功就分配新的
65 | if (retryTime < 3) {
66 | return obtain(retryTime++);
67 | } else {
68 | return (T) factory.createNew();
69 | }
70 | }
71 | }
72 |
73 | public void clear() {
74 |
75 | }
76 |
77 | public interface RecyclableFactory {
78 | T createNew();
79 | }
80 |
81 | public abstract static class RecyclableObject {
82 | AtomicBoolean isIdle = new AtomicBoolean(true);
83 |
84 | }
85 |
86 |
87 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/mlog/MAopHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.mlog;
2 |
3 | /**
4 | * 创建时间: 2018/10/9
5 | * 类描述:自定义aop处理的处理类
6 | *
7 | * 多线程执行同一方法
8 | * 通过ThreadLocal变量解决
9 | *
10 | * 递归执行同一方法
11 | * 在同一线程中通过栈解决
12 | *
13 | * @author 秋刀鱼
14 | * @version 1.0
15 | */
16 | public interface MAopHandler {
17 | /**
18 | * 如果before有数据需要传递给after,使用ThreadLocal来实现
19 | *
20 | * @param classOrInstance
21 | * @param params
22 | * @param args
23 | */
24 | void before(String[] params, Object classOrInstance, Object[] args);
25 |
26 |
27 | /**
28 | * mode 1-正常返回 0-exception处退出
29 | *
30 | * @param mode
31 | * @param returnValue
32 | * @param params
33 | * @param classOrInstance
34 | * @param args
35 | */
36 | void after(int mode, Object returnValue, String[] params, Object classOrInstance, Object[] args);
37 |
38 | /**
39 | * returnValue
40 | *
41 | * @param classOrInstance
42 | * @param params
43 | * @param args
44 | */
45 | void exception(Object exception, String[] params, Object classOrInstance, Object[] args);
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/mlog/MethodValueAopHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.mlog;
2 |
3 | import com.qiudaoyu.monitor.analysis.network.NetMonitor;
4 | import com.qiudaoyu.monitor.utils.MethodValue;
5 | import com.qiudaoyu.monitor.analysis.network.NetMonitor;
6 | import com.qiudaoyu.monitor.utils.MethodValue;
7 |
8 | import okhttp3.OkHttpClient;
9 |
10 | /**
11 | * 创建时间: 2018/10/9
12 | * 类描述:自定义aop处理的处理类
13 | *
14 | * 多线程执行同一方法
15 | * 通过ThreadLocal变量解决
16 | *
17 | * 递归执行同一方法
18 | * 在同一线程中通过栈解决
19 | *
20 | * @author 秋刀鱼
21 | * @version 1.0
22 | */
23 | public abstract class MethodValueAopHandler implements MAopHandler {
24 | /**
25 | * 如果before有数据需要传递给after,使用ThreadLocal来实现
26 | *
27 | * @param classOrInstance
28 | * @param params
29 | * @param args
30 | */
31 | public void before(String[] params, Object classOrInstance, Object[] args) {
32 | MethodValue.methodEnter();
33 | if (params != null && params.length == 1
34 | && params[0].equals("okhttp3.OkHttpClient$Builder.build")
35 | && classOrInstance != null) {
36 | NetMonitor.beforeOkHttpBuild((OkHttpClient.Builder) (classOrInstance));
37 | }
38 | vBefore(params, classOrInstance, args);
39 | }
40 |
41 |
42 | /**
43 | * mode 1-正常返回 0-exception处退出
44 | *
45 | * @param mode
46 | * @param returnValue
47 | * @param params
48 | * @param classOrInstance
49 | * @param args
50 | */
51 | public void after(int mode, Object returnValue, String[] params, Object classOrInstance, Object[] args) {
52 | try {
53 | vAfter(mode, returnValue, params, classOrInstance, args);
54 | } finally {
55 | MethodValue.methodExit();
56 | }
57 | }
58 |
59 | public Object getValue() {
60 | return MethodValue.getValue();
61 | }
62 |
63 | public void setValue(Object value) {
64 | MethodValue.setValue(value);
65 | }
66 |
67 | /**
68 | * returnValue
69 | *
70 | * @param classOrInstance
71 | * @param params
72 | * @param args
73 | */
74 | public void exception(Object exception, String[] params, Object classOrInstance, Object[] args) {
75 | vException(exception, params, classOrInstance, args);
76 | }
77 |
78 | /**
79 | * 如果before有数据需要传递给after,使用ThreadLocal来实现
80 | *
81 | * @param classOrInstance
82 | * @param params
83 | * @param args
84 | */
85 | public abstract void vBefore(String[] params, Object classOrInstance, Object[] args);
86 |
87 |
88 | /**
89 | * mode 1-正常返回 0-exception处退出
90 | *
91 | * @param mode
92 | * @param returnValue
93 | * @param params
94 | * @param classOrInstance
95 | * @param args
96 | */
97 | public abstract void vAfter(int mode, Object returnValue, String[] params, Object classOrInstance, Object[] args);
98 |
99 | /**
100 | * returnValue
101 | *
102 | * @param classOrInstance
103 | * @param params
104 | * @param args
105 | */
106 | public abstract void vException(Object exception, String[] params, Object classOrInstance, Object[] args);
107 |
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/mlog/TrackRunable.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.mlog;
2 |
3 | /**
4 | * 创建时间: 2018/10/15
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public abstract class TrackRunable implements Runnable {
11 | public abstract String getParentId();
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/mlog/annotation/MAop.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.mlog.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 创建时间: 2018/10/9
10 | * 类描述: 在当前方法前后插入代码
11 | *
12 | * @author 秋刀鱼
13 | * @version 1.0
14 | */
15 | @Retention(RetentionPolicy.RUNTIME)
16 | @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
17 | public @interface MAop {
18 |
19 | String[] params() default {};
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/log/mlog/annotation/ParentId.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.log.mlog.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 创建时间: 2018/10/9
10 | * 类描述:设置当前方法产生的事件的父节点
11 | *
12 | * @author 秋刀鱼
13 | * @version 1.0
14 | */
15 | @Retention(RetentionPolicy.RUNTIME)
16 | @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
17 | public @interface ParentId {
18 | String parentId() default "";
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/remote/Command.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.remote;
2 |
3 | /**
4 | * 创建时间: 2018/12/14
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public class Command {
11 | public static final int TYPE_SHELL = 0;
12 |
13 |
14 | public static final int TYPE_LUA = 100000;
15 |
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/remote/RemotCommandService.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.remote;
2 |
3 | /**
4 | * 创建时间: 2018/12/7
5 | * 类描述:
6 | * 可以通过推送通道执行远程命令
7 | * 使用lua来具备动态执行功能
8 | * 执行进程java方法
9 | * Runtime执行命令行
10 | *
11 | * @author 秋刀鱼
12 | * @version 1.0
13 | */
14 | public class RemotCommandService {
15 |
16 | public static void handleCommand(Command command) {
17 |
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/upload/UploadServiceInterface.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.upload;
2 |
3 |
4 | /**
5 | * 创建时间: 2018/9/26
6 | * 类描述:
7 | * 上传日志类
8 | *
9 | * @author 秋刀鱼
10 | * @version 1.0
11 | */
12 |
13 | public interface UploadServiceInterface {
14 |
15 | void initialize(T arg);
16 |
17 |
18 | void sendData(Object data);
19 |
20 | void setForground(boolean isForgroud);
21 |
22 | void shutDown();
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/ContentLisenter.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | /**
4 | * 创建时间: 2018/12/11
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public interface ContentLisenter {
11 | void content(String content);
12 |
13 | void error(Exception e,String s);
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/EmptyUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import android.os.Build;
4 | import android.util.SparseArray;
5 | import android.util.SparseBooleanArray;
6 | import android.util.SparseIntArray;
7 | import android.util.SparseLongArray;
8 |
9 | import java.lang.reflect.Array;
10 | import java.util.Collection;
11 | import java.util.Map;
12 |
13 | /**
14 | * 创建时间: 2018/8/14 下午2:31
15 | * 类描述: 判空相关工具类
16 | *
17 | * @author 木棉
18 | */
19 | public class EmptyUtils {
20 |
21 | public static final String EMPTY_STR = "";
22 |
23 | private EmptyUtils() {
24 | throw new UnsupportedOperationException("u can't instantiate me...");
25 | }
26 |
27 | /**
28 | * 判断对象是否为空
29 | *
30 | * @param obj 对象
31 | * @return {@code true}: 为空
{@code false}: 不为空
32 | */
33 | public static boolean isEmpty(Object obj) {
34 | if (obj == null) {
35 | return true;
36 | }
37 | if (obj instanceof String && obj.toString().length() == 0) {
38 | return true;
39 | }
40 | if (obj instanceof StringBuilder && obj.toString().length() == 0) {
41 | return true;
42 | }
43 | if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
44 | return true;
45 | }
46 | if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
47 | return true;
48 | }
49 | if (obj instanceof Map && ((Map) obj).isEmpty()) {
50 | return true;
51 | }
52 | if (obj instanceof SparseArray && ((SparseArray) obj).size() == 0) {
53 | return true;
54 | }
55 | if (obj instanceof SparseBooleanArray && ((SparseBooleanArray) obj).size() == 0) {
56 | return true;
57 | }
58 | if (obj instanceof SparseIntArray && ((SparseIntArray) obj).size() == 0) {
59 | return true;
60 | }
61 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
62 | if (obj instanceof SparseLongArray && ((SparseLongArray) obj).size() == 0) {
63 | return true;
64 | }
65 | }
66 | return false;
67 | }
68 |
69 | /**
70 | * 判断对象是否非空
71 | *
72 | * @param obj 对象
73 | * @return {@code true}: 非空
{@code false}: 空
74 | */
75 | public static boolean isNotEmpty(Object obj) {
76 | return !isEmpty(obj);
77 | }
78 |
79 | /**
80 | * 只要任意一个为空,并为true
81 | *
82 | * @param objects
83 | * @return
84 | */
85 | public static boolean isOneEmpty(Object... objects) {
86 | if (isEmpty(objects)) return true;
87 | for (Object object : objects) {
88 | if (isEmpty(object)) {
89 | return true;
90 | }
91 | }
92 | return false;
93 | }
94 |
95 | /**
96 | * 所有都不为空
97 | */
98 | public static boolean isAllNotEmpty(Object... objects) {
99 | return !isOneEmpty(objects);
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/IoUtil.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import java.io.Closeable;
4 | import java.io.IOException;
5 |
6 | /**
7 | *
8 | */
9 |
10 | public class IoUtil {
11 | public static final int DEFAULT_BUFFER_SIZE = 32768;
12 |
13 | private IoUtil() {
14 | }
15 |
16 | public static void closeSilently(Closeable closeable) {
17 | if (closeable != null) {
18 | try {
19 | closeable.close();
20 | } catch (IOException var2) {
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/JSONUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 |
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | public class JSONUtils {
8 |
9 | public static String optionalStringKey(JSONObject o, String k) throws JSONException {
10 | if (o.has(k) && !o.isNull(k)) {
11 | return o.getString(k);
12 | }
13 | return null;
14 | }
15 |
16 | private static void addIndentBlank(StringBuilder sb, int indent) {
17 | try {
18 | for (int i = 0; i < indent; i++) {
19 | sb.append('\t');
20 | }
21 | } catch (Exception e) {
22 | e.printStackTrace();
23 | }
24 | }
25 |
26 | public static String formatJson(String jsonStr) {
27 | try {
28 | if (null == jsonStr || "".equals(jsonStr)) {
29 | return "";
30 | }
31 | StringBuilder sb = new StringBuilder();
32 | char last = '\0';
33 | char current = '\0';
34 | int indent = 0;
35 | boolean isInQuotationMarks = false;
36 | for (int i = 0; i < jsonStr.length(); i++) {
37 | last = current;
38 | current = jsonStr.charAt(i);
39 | switch (current) {
40 | case '"':
41 | if (last != '\\') {
42 | isInQuotationMarks = !isInQuotationMarks;
43 | }
44 | sb.append(current);
45 | break;
46 | case '{':
47 | case '[':
48 | sb.append(current);
49 | if (!isInQuotationMarks) {
50 | sb.append('\n');
51 | indent++;
52 | addIndentBlank(sb, indent);
53 | }
54 | break;
55 | case '}':
56 | case ']':
57 | if (!isInQuotationMarks) {
58 | sb.append('\n');
59 | indent--;
60 | addIndentBlank(sb, indent);
61 | }
62 | sb.append(current);
63 | break;
64 | case ',':
65 | sb.append(current);
66 | if (last != '\\' && !isInQuotationMarks) {
67 | sb.append('\n');
68 | addIndentBlank(sb, indent);
69 | }
70 | break;
71 | default:
72 | sb.append(current);
73 | }
74 | }
75 |
76 | return sb.toString();
77 | } catch (Exception e) {
78 | e.printStackTrace();
79 | return "";
80 | }
81 | }
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/MD5Utils.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.UnsupportedEncodingException;
8 | import java.security.MessageDigest;
9 | import java.security.NoSuchAlgorithmException;
10 |
11 | /**
12 | * 创建时间: 2017/8/28 上午11:19
13 | * 类描述:
14 | *
15 | * @author 木棉
16 | */
17 |
18 | public class MD5Utils {
19 |
20 | private static final String[] HEX_DIGITS = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
21 |
22 | private MD5Utils() {
23 | }
24 |
25 | private static String byteArrayToHexString(byte[] b) {
26 | StringBuffer buf = new StringBuffer();
27 | for (byte aB : b) {
28 | buf.append(byteToHexString(aB));
29 | }
30 | return buf.toString();
31 | }
32 |
33 | private static String byteToHexString(byte b) {
34 | return HEX_DIGITS[(b & 240) >> 4] + HEX_DIGITS[b & 15];
35 | }
36 |
37 | public static String encode(String origin) {
38 | if (origin == null) {
39 | throw new IllegalArgumentException("MULTI_000523");
40 | } else {
41 | String resultString = origin;
42 | try {
43 | MessageDigest e = MessageDigest.getInstance("MD5");
44 | try {
45 | resultString = byteArrayToHexString(e.digest(resultString.getBytes("UTF-8")));
46 | } catch (UnsupportedEncodingException var4) {
47 | var4.printStackTrace();
48 | }
49 | return resultString;
50 | } catch (NoSuchAlgorithmException var5) {
51 | return null;
52 | }
53 | }
54 | }
55 | /**
56 | * 对输入流生成校验码.
57 | * @param in 输入流.
58 | * @return 生成的校验码.
59 | */
60 | public static String encode(InputStream in) {
61 | if (in == null) {
62 | throw new NullPointerException("origin == null");
63 | }
64 | String resultString = null;
65 | try {
66 | MessageDigest md = MessageDigest.getInstance("MD5");
67 | byte[] buffer = new byte[1024 * 1024];
68 | int len = 0;
69 | while ((len = in.read(buffer)) > 0) {
70 | md.update(buffer, 0, len);
71 | }
72 | resultString = byteArrayToHexString(md.digest());
73 | } catch (NoSuchAlgorithmException e) {
74 | Log.e("MD5Util","NoSuchAlgorithmException",e);
75 | } catch (IOException e) {
76 | Log.e("MD5Util","InputStream read error",e);
77 | }
78 | return resultString;
79 | }
80 | }
81 |
82 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/MethodValue.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import java.util.Stack;
4 |
5 | /**
6 | * 创建时间: 2018/12/6
7 | * 类描述:
8 | *
9 | * 方法内有效的值
10 | *
11 | * 需要在方法开始 调用methodEnter
12 | *
13 | * 需要在方法结束/异常 调用methodExit
14 | *
15 | * methodEnter/methodExit 需要对称调用
16 | *
17 | * @author 秋刀鱼
18 | * @version 1.0
19 | */
20 | public class MethodValue {
21 |
22 | private static ThreadLocal> locals = new ThreadLocal<>();
23 |
24 | public static void methodEnter() {
25 | if (locals.get() == null) {
26 | locals.set(new Stack<>());
27 | }
28 | locals.get().push(null);
29 | }
30 |
31 | public static Object getValue() {
32 | if (locals.get() == null) {
33 | locals.set(new Stack<>());
34 | locals.get().push(null);
35 | }
36 | return locals.get().peek();
37 | }
38 |
39 | public static void setValue(Object data) {
40 | if (locals.get() == null) {
41 | locals.set(new Stack<>());
42 | locals.get().push(null);
43 | }
44 | locals.get().pop();
45 | locals.get().push(data);
46 | }
47 |
48 | public static void methodExit() {
49 | if (locals.get() == null) {
50 | locals.set(new Stack<>());
51 | locals.get().push(null);
52 | }
53 | locals.get().pop();
54 | }
55 |
56 | public static void clear() {
57 | locals.set(null);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/ProcessUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import android.content.Context;
4 | import android.content.pm.ApplicationInfo;
5 | import android.content.pm.PackageManager;
6 |
7 | /**
8 | * 创建时间: 2018/12/4
9 | * 类描述:
10 | *
11 | * @author 秋刀鱼
12 | * @version 1.0
13 | */
14 | public class ProcessUtils {
15 | /**
16 | * 获取当前应用uid
17 | *
18 | * @return
19 | */
20 | public static int getUid(Context context) {
21 | try {
22 | PackageManager pm = context.getPackageManager();
23 | //修改
24 | ApplicationInfo ai = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
25 | return ai.uid;
26 | } catch (PackageManager.NameNotFoundException e) {
27 | e.printStackTrace();
28 | }
29 | return -1;
30 | }
31 |
32 | public static void killProcessAndExit() {
33 | android.os.Process.killProcess(android.os.Process.myPid());
34 | System.exit(10);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/SharedPreferencesUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 | import java.lang.reflect.InvocationTargetException;
7 | import java.lang.reflect.Method;
8 | import java.util.Map;
9 |
10 | /**
11 | * 创建时间: 16/10/13 上午11:33
12 | * 类描述:
13 | * 对SharedPreference的使用做了建议的封装,对外公布出put,get,remove,clear等等方法
14 | * 注意一点,里面所有的commit操作使用了SharedPreferencesCompat.apply进行了替代,目的是尽可能的使用apply代替commit
15 | * 首先说下为什么,因为commit方法是同步的,并且我们很多时候的commit操作都是UI线程中,毕竟是IO操作,尽可能异步;
16 | * 所以使用apply进行替代,apply异步的进行写入; 但是apply相当于commit来说是new API,为了更好的兼容,做了适配;
17 | */
18 | public class SharedPreferencesUtils {
19 |
20 | /**
21 | * 保存在手机里面的文件名
22 | */
23 | public static String FILE_NAME = "monitor_data";
24 |
25 |
26 | private static SharedPreferences file(Context context, String fileName) {
27 | return context.getSharedPreferences(fileName, Context.MODE_PRIVATE);
28 | }
29 |
30 | /**
31 | * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
32 | */
33 | public static void put(Context context, String fileName, String key, Object object) {
34 | SharedPreferences sp = file(context, fileName);
35 | SharedPreferences.Editor editor = sp.edit();
36 | if (object instanceof String) {
37 | editor.putString(key, (String) object);
38 | } else if (object instanceof Integer) {
39 | editor.putInt(key, (Integer) object);
40 | } else if (object instanceof Boolean) {
41 | editor.putBoolean(key, (Boolean) object);
42 | } else if (object instanceof Float || object instanceof Double) {
43 | editor.putFloat(key, (Float) object);
44 | } else if (object instanceof Long) {
45 | editor.putLong(key, (Long) object);
46 | } else {
47 | editor.putString(key, object.toString());
48 | }
49 | SharedPreferencesCompat.apply(editor);
50 | }
51 |
52 |
53 | /**
54 | * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
55 | */
56 | public static Object get(Context context, String file, String key, Object defaultObject) {
57 | SharedPreferences sp = file(context, file);
58 | if (defaultObject instanceof String) {
59 | return sp.getString(key, (String) defaultObject);
60 | } else if (defaultObject instanceof Integer) {
61 | return sp.getInt(key, (Integer) defaultObject);
62 | } else if (defaultObject instanceof Boolean) {
63 | return sp.getBoolean(key, (Boolean) defaultObject);
64 | } else if (defaultObject instanceof Float || defaultObject instanceof Double) {
65 | return sp.getFloat(key, (Float) defaultObject);
66 | } else if (defaultObject instanceof Long) {
67 | return sp.getLong(key, (Long) defaultObject);
68 | }
69 | return defaultObject;
70 | }
71 |
72 | /**
73 | * 移除某个key值已经对应的值
74 | */
75 | public static void remove(Context context, String fileName, String key) {
76 | SharedPreferences sp = file(context, fileName);
77 | SharedPreferences.Editor editor = sp.edit();
78 | editor.remove(key);
79 | SharedPreferencesCompat.apply(editor);
80 | }
81 |
82 | /**
83 | * 清除所有数据
84 | */
85 | public static void clear(Context context, String fileName) {
86 | SharedPreferences sp = file(context, fileName);
87 | SharedPreferences.Editor editor = sp.edit();
88 | editor.clear();
89 | SharedPreferencesCompat.apply(editor);
90 | }
91 |
92 | /**
93 | * 查询某个key是否已经存在
94 | */
95 | public static boolean contains(Context context, String key) {
96 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
97 | return sp.contains(key);
98 | }
99 |
100 | /**
101 | * 返回所有的键值对
102 | */
103 | public static Map getAll(Context context) {
104 | SharedPreferences sp = file(context, FILE_NAME);
105 | return sp.getAll();
106 | }
107 |
108 | /**
109 | * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
110 | */
111 | private static class SharedPreferencesCompat {
112 | private static final Method sApplyMethod = findApplyMethod();
113 |
114 | /**
115 | * 反射查找apply的方法
116 | */
117 | @SuppressWarnings({"unchecked", "rawtypes"})
118 | private static Method findApplyMethod() {
119 | try {
120 | Class clz = SharedPreferences.Editor.class;
121 | return clz.getMethod("apply");
122 | } catch (NoSuchMethodException e) {
123 | }
124 |
125 | return null;
126 | }
127 |
128 | /**
129 | * 如果找到则使用apply执行,否则使用commit
130 | */
131 | public static void apply(SharedPreferences.Editor editor) {
132 | try {
133 | if (sApplyMethod != null) {
134 | sApplyMethod.invoke(editor);
135 | return;
136 | }
137 | } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
138 | e.printStackTrace();
139 | }
140 | editor.commit();
141 | }
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/StacktraceUtil.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.ArrayList;
5 | import java.util.LinkedHashMap;
6 | import java.util.List;
7 | import java.util.Locale;
8 | import java.util.Map;
9 |
10 | /**
11 | *
12 | */
13 | public class StacktraceUtil {
14 | private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
15 |
16 | /**
17 | * 原始的堆栈信息转换为字符串类型的堆栈信息
18 | *
19 | * @param ts
20 | * @return
21 | */
22 | public static Map convertToStackString(Map ts) {
23 | // 筛选之后的堆栈
24 | Map filterMap = new LinkedHashMap<>();
25 | for (Long key : ts.keySet()) {
26 | StackTraceElement[] value = ts.get(key);
27 | if (!filterMap.containsValue(value)) {// 筛选一下是否存在堆栈信息相同的
28 | filterMap.put(key, value);
29 | }
30 | }
31 | // 转换为字符串
32 | Map result = new LinkedHashMap<>();
33 | for (Map.Entry entry : filterMap.entrySet()) {
34 | result.put(TIME_FORMATTER.format(entry.getKey()), getStackString(entry.getValue()));
35 | }
36 | return result;
37 | }
38 |
39 | private static String getStackString(StackTraceElement[] stackTraceElements) {
40 | StringBuilder builder = new StringBuilder();
41 | for (StackTraceElement traceElement : stackTraceElements) {
42 | builder.append(String.valueOf(traceElement));
43 | }
44 | return builder.toString();
45 | }
46 |
47 | private static List getStack(List stackTraceElements) {
48 | List stackList = new ArrayList<>();
49 | for (StackTraceElement traceElement : stackTraceElements) {
50 | stackList.add(String.valueOf(traceElement));
51 | }
52 | return stackList;
53 | }
54 |
55 | public static List getStack(StackTraceElement... stackTraceElements) {
56 | List stackList = new ArrayList<>();
57 | for (StackTraceElement traceElement : stackTraceElements) {
58 | stackList.add(String.valueOf(traceElement));
59 | }
60 | return stackList;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/ThreadUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | /**
4 | * 创建时间: 2018/9/25
5 | * 类描述:
6 | *
7 | * @author 秋刀鱼
8 | * @version 1.0
9 | */
10 | public class ThreadUtils {
11 |
12 | /**
13 | * 获取当前所有激活的线程
14 | * @return
15 | */
16 | public static Thread[] getAllThreads() {
17 | ThreadGroup group = Thread.currentThread().getThreadGroup();
18 | ThreadGroup topGroup = group;
19 | // 遍历线程组树,获取根线程组
20 | while (group != null) {
21 | topGroup = group;
22 | group = group.getParent();
23 | }
24 | // 激活的线程数再加一倍,防止枚举时有可能刚好有动态线程生成
25 | int slackSize = topGroup.activeCount() * 2;
26 | Thread[] slackThreads = new Thread[slackSize];
27 | // 获取根线程组下的所有线程,返回的actualSize便是最终的线程数
28 | int actualSize = topGroup.enumerate(slackThreads);
29 | Thread[] atualThreads = new Thread[actualSize];
30 | // 复制slackThreads中有效的值到atualThreads
31 | System.arraycopy(slackThreads, 0, atualThreads, 0, actualSize);
32 | System.out.println("Threads size is " + atualThreads.length);
33 | return atualThreads;
34 | }
35 |
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/com/qiudaoyu/monitor/utils/UUIDGenerator.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.utils;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 |
5 | /**
6 | * 用于生成ID.
7 | *
8 | * @author 黄晓峰
9 | * @version $Revision$
10 | */
11 | public class UUIDGenerator {
12 | private static final int ID_LENGTH = 36;
13 | private static final int INT_BIT = 8;
14 | private static final int STR_BIT = 8;
15 | private static final int SHORT_BIT = 4;
16 | private static final int JVM_BIT = 8;
17 | private static final int HI = 32;
18 | private static final int JVM = (int) (System.currentTimeMillis() >>> JVM_BIT);
19 | private static short counter = (short) 0;
20 | private String entityId = "10000000";
21 |
22 | /**
23 | * 构造ID生成器.
24 | */
25 | public UUIDGenerator() {
26 |
27 | }
28 |
29 | public UUIDGenerator setEntityId(String entityId) {
30 | if (StringUtils.isNotBlank(entityId)) {
31 | if (entityId.length() == 8) {
32 | this.entityId = entityId;
33 | }
34 | }
35 | return this;
36 | }
37 |
38 |
39 | /**
40 | * 得到JVM相关信息.
41 | * 这里是JVM启动时间.
42 | *
43 | * @return JVM相关信息.
44 | */
45 | protected int getJVM() {
46 | return JVM;
47 | }
48 |
49 | /**
50 | * 得到当前计数.
51 | * 可防重复.
52 | *
53 | * @return 当前计数.
54 | */
55 | protected short getCount() {
56 | synchronized (UUIDGenerator.class) {
57 | if (counter < 0) {
58 | counter = 0;
59 | }
60 | return counter++;
61 | }
62 | }
63 |
64 | /**
65 | * 得到高位时间.
66 | *
67 | * @return 高位时间.
68 | */
69 | protected short getHiTime() {
70 | return (short) (System.currentTimeMillis() >>> HI);
71 | }
72 |
73 | /**
74 | * 得到低位时间.
75 | *
76 | * @return 低位时间.
77 | */
78 | protected int getLoTime() {
79 | return (int) System.currentTimeMillis();
80 | }
81 |
82 | /**
83 | * 格式化int型数据.
84 | * 占八位.
85 | *
86 | * @param intval int型的值.
87 | * @return 格式化后的字符串.
88 | */
89 | protected String format(int intval) {
90 | String formatted = Integer.toHexString(intval);
91 | StringBuilder buf = new StringBuilder("00000000");
92 | buf.replace(INT_BIT - formatted.length(), INT_BIT, formatted);
93 | return buf.toString();
94 | }
95 |
96 | /**
97 | * 格式化short型数据.
98 | * 占四位.
99 | *
100 | * @param shortval short型的值.
101 | * @return 格式化后的字符串.
102 | */
103 | protected String format(short shortval) {
104 | String formatted = Integer.toHexString(shortval);
105 | StringBuilder buf = new StringBuilder("0000");
106 | buf.replace(SHORT_BIT - formatted.length(), SHORT_BIT, formatted);
107 | return buf.toString();
108 | }
109 |
110 | /**
111 | * 得到一个UUID.
112 | *
113 | * @return 新的UUID.
114 | */
115 | public String generate() {
116 | return "" + entityId +
117 | format(getJVM()) + format(getHiTime()) +
118 | format(getLoTime()) + format(getCount());
119 | }
120 |
121 | /**
122 | * 格式化字符串型数据.
123 | * 占八位.
124 | *
125 | * @param stringval 字符串型的值.
126 | * @return 格式化后的结果.
127 | */
128 | protected String format(String stringval) {
129 | if (stringval == null) {
130 | stringval = "";
131 | }
132 | stringval = stringval.length() > STR_BIT ? stringval.substring(
133 | stringval.length() - STR_BIT, stringval.length()) : stringval;
134 | StringBuilder buf = new StringBuilder("00000000");
135 | buf.replace(STR_BIT - stringval.length(), STR_BIT, stringval);
136 | return buf.toString();
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/core/src/main/java/proto/config.proto:
--------------------------------------------------------------------------------
1 | //proto的版本
2 |
3 | syntax = "proto3";
4 | option java_package = "com.qiudaoyu.monitor.pb";
5 | option java_outer_classname = "ConfigProto";
6 |
7 | message ConfigTable {
8 | int32 version = 1;
9 | repeated HaseNode hashIndexTable = 2;
10 | }
11 |
12 | message HaseNode {
13 | int32 hashA = 1;
14 | int32 hashB = 2;
15 | bool isExist = 3;
16 | MethodConfig data = 4;
17 | }
18 |
19 | message MethodConfig {
20 | int32 beforeExceptionAfter = 1;
21 | string luaString = 2;
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/core/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/debug/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/debug/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 27
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 27
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: 'libs', include: ['*.jar'])
29 |
30 | implementation 'com.android.support:appcompat-v7:27.1.1'
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
33 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
34 | }
35 |
--------------------------------------------------------------------------------
/debug/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/debug/src/androidTest/java/com/qiudaoyu/monitor/debug/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.debug;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.qiudaoyu.monitor.debug.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/debug/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/debug/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Debug
3 |
4 |
--------------------------------------------------------------------------------
/debug/src/test/java/com/qiudaoyu/monitor/debug/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.qiudaoyu.monitor.debug;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/flog/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/flog/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'maven'
3 | android {
4 | compileSdkVersion 26
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 26
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: 'libs', include: ['*.jar'])
29 |
30 | implementation commDependencies.supp
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
33 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
34 | implementation commDependencies.commons
35 | }
36 |
37 | //uploadArchives {
38 | // repositories.mavenDeployer {
39 | //
40 | // repository(url: RELEASE_REPOSITORY_URL) {
41 | // authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
42 | // }
43 | //
44 | // snapshotRepository(url: SNAPSHOT_REPOSITORY_URL) {
45 | // authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
46 | // }
47 | // pom.project {
48 | // groupId "com.zmsoft.log"
49 | // artifactId "flog"
50 | // version "1.0.0-snapchat"
51 | // }
52 | // }
53 | //}
54 |
--------------------------------------------------------------------------------
/flog/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/flog/src/androidTest/java/monitor/zmsoft/com/flog/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package monitor.zmsoft.com.flog;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("monitor.zmsoft.com.flog.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/flog/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/flog/src/main/java/com/tencent/mars/xlog/Xlog.java:
--------------------------------------------------------------------------------
1 | package com.tencent.mars.xlog;
2 |
3 |
4 | @SuppressWarnings("JniMissingFunction")
5 | public class Xlog implements Log.LogImp {
6 |
7 | public static final int LEVEL_ALL = 0;
8 | public static final int LEVEL_VERBOSE = 0;
9 | public static final int LEVEL_DEBUG = 1;
10 | public static final int LEVEL_INFO = 2;
11 | public static final int LEVEL_WARNING = 3;
12 | public static final int LEVEL_ERROR = 4;
13 | public static final int LEVEL_FATAL = 5;
14 | public static final int LEVEL_NONE = 6;
15 |
16 | public static final int AppednerModeAsync = 0;
17 | public static final int AppednerModeSync = 1;
18 |
19 | public static void open(boolean isLoadLib, int level, int mode, String cacheDir, String logDir, String nameprefix, String pubkey) {
20 | if (isLoadLib) {
21 | System.loadLibrary("stlport_shared");
22 | System.loadLibrary("marsxlog");
23 | }
24 |
25 | appenderOpen(level, mode, cacheDir, logDir, nameprefix, pubkey);
26 | }
27 |
28 | private static String decryptTag(String tag) {
29 | return tag;
30 | }
31 |
32 | public static native void logWrite(XLoggerInfo logInfo, String log);
33 |
34 | public static native void logWrite2(int level, String tag, String filename, String funcname, int line, int pid, long tid, long maintid, String log);
35 |
36 | public static native void setAppenderMode(int mode);
37 |
38 | public static native void setConsoleLogOpen(boolean isOpen); //set whether the console prints log
39 |
40 | public static native void setErrLogOpen(boolean isOpen); //set whether the prints err log into a separate file
41 |
42 | public static native void appenderOpen(int level, int mode, String cacheDir, String logDir, String nameprefix, String pubkey);
43 |
44 | @Override
45 | public void logV(String tag, String filename, String funcname, int line, int pid, long tid, long maintid, String log) {
46 | logWrite2(LEVEL_VERBOSE, decryptTag(tag), filename, funcname, line, pid, tid, maintid, log);
47 | }
48 |
49 | @Override
50 | public void logD(String tag, String filename, String funcname, int line, int pid, long tid, long maintid, String log) {
51 | logWrite2(LEVEL_DEBUG, decryptTag(tag), filename, funcname, line, pid, tid, maintid, log);
52 | }
53 |
54 | @Override
55 | public void logI(String tag, String filename, String funcname, int line, int pid, long tid, long maintid, String log) {
56 | logWrite2(LEVEL_INFO, decryptTag(tag), filename, funcname, line, pid, tid, maintid, log);
57 | }
58 |
59 | @Override
60 | public void logW(String tag, String filename, String funcname, int line, int pid, long tid, long maintid, String log) {
61 | logWrite2(LEVEL_WARNING, decryptTag(tag), filename, funcname, line, pid, tid, maintid, log);
62 | }
63 |
64 | @Override
65 | public void logE(String tag, String filename, String funcname, int line, int pid, long tid, long maintid, String log) {
66 | logWrite2(LEVEL_ERROR, decryptTag(tag), filename, funcname, line, pid, tid, maintid, log);
67 | }
68 |
69 | @Override
70 | public void logF(String tag, String filename, String funcname, int line, int pid, long tid, long maintid, String log) {
71 | logWrite2(LEVEL_FATAL, decryptTag(tag), filename, funcname, line, pid, tid, maintid, log);
72 | }
73 |
74 | @Override
75 | public native int getLogLevel();
76 |
77 | public static native void setLogLevel(int logLevel);
78 |
79 | @Override
80 | public native void appenderClose();
81 |
82 | @Override
83 | public native void appenderFlush(boolean isSync);
84 |
85 | static class XLoggerInfo {
86 | public int level;
87 | public String tag;
88 | public String filename;
89 | public String funcname;
90 | public int line;
91 | public long pid;
92 | public long tid;
93 | public long maintid;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/flog/src/main/jniLibs/armeabi-v7a/libmarsxlog.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/flog/src/main/jniLibs/armeabi-v7a/libmarsxlog.so
--------------------------------------------------------------------------------
/flog/src/main/jniLibs/armeabi-v7a/libstlport_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/flog/src/main/jniLibs/armeabi-v7a/libstlport_shared.so
--------------------------------------------------------------------------------
/flog/src/main/jniLibs/x86_64/libmarsxlog.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/flog/src/main/jniLibs/x86_64/libmarsxlog.so
--------------------------------------------------------------------------------
/flog/src/main/jniLibs/x86_64/libstlport_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/flog/src/main/jniLibs/x86_64/libstlport_shared.so
--------------------------------------------------------------------------------
/flog/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | FLog
3 |
4 |
--------------------------------------------------------------------------------
/flog/src/test/java/monitor/zmsoft/com/flog/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package monitor.zmsoft.com.flog;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Mar 28 10:08:01 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/plugin/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | /build/
3 |
--------------------------------------------------------------------------------
/plugin/build.gradle:
--------------------------------------------------------------------------------
1 | def config = rootProject.ext
2 | apply plugin: 'groovy'
3 | apply plugin: 'maven'
4 |
5 | repositories {
6 | google()
7 | mavenCentral()
8 | jcenter()
9 | }
10 |
11 | dependencies {
12 | implementation gradleApi() //gradle sdk
13 | implementation localGroovy() //groovy sdk
14 | implementation commDependencies.gradle
15 | implementation commDependencies.transform
16 | implementation commDependencies.asm
17 |
18 | }
19 | uploadArchives {
20 | repositories.mavenDeployer {
21 |
22 | repository(url:uri('../repo')) {
23 |
24 | }
25 |
26 | snapshotRepository(url:uri('../repo')) {
27 |
28 | }
29 | pom.project {
30 | groupId "com.sanyouyu.monitor"
31 | artifactId "plugin"
32 | version "${config.deployVersion}"
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/analytics/activity/MasAnalyticsDefaultMethodVisitor.groovy:
--------------------------------------------------------------------------------
1 | package com.mas.analytics.activity
2 |
3 | import com.mas.plugin.Logger
4 | import org.objectweb.asm.*
5 | import org.objectweb.asm.commons.AdviceAdapter
6 |
7 | public class MasAnalyticsDefaultMethodVisitor extends AdviceAdapter {
8 |
9 | String methodName
10 |
11 | public MasAnalyticsDefaultMethodVisitor(MethodVisitor mv, int access, String name, String desc) {
12 | super(Opcodes.ASM5, mv, access, name, desc)
13 | methodName = name
14 | Logger.info("analy 开始扫描方法:${Logger.accCode2String(access)} ${methodName}${desc}")
15 | }
16 |
17 | /**
18 | * 表示 ASM 开始扫描这个方法
19 | */
20 | @Override
21 | void visitCode() {
22 | super.visitCode()
23 | }
24 |
25 | @Override
26 | public void visitMethodInsn(int opcode, String owner, String name, String desc) {
27 | super.visitMethodInsn(opcode, owner, name, desc)
28 | }
29 |
30 | @Override
31 | public void visitAttribute(Attribute attribute) {
32 | super.visitAttribute(attribute)
33 | }
34 |
35 | /**
36 | * 表示方法输出完毕
37 | */
38 | @Override
39 | public void visitEnd() {
40 | Logger.info("annly 结束扫描方法:${methodName}\n")
41 | super.visitEnd()
42 | }
43 |
44 | @Override
45 | public void visitFieldInsn(int opcode, String owner, String name, String desc) {
46 | super.visitFieldInsn(opcode, owner, name, desc)
47 | }
48 |
49 | @Override
50 | public void visitIincInsn(int var, int increment) {
51 | super.visitIincInsn(var, increment)
52 | }
53 |
54 | @Override
55 | public void visitIntInsn(int i, int i1) {
56 | super.visitIntInsn(i, i1)
57 | }
58 |
59 | /**
60 | * 该方法是 visitEnd 之前调用的方法,可以反复调用。用以确定类方法在执行时候的堆栈大小。
61 | * @param maxStack
62 | * @param maxLocals
63 | */
64 | @Override
65 | public void visitMaxs(int maxStack, int maxLocals) {
66 | super.visitMaxs(maxStack, maxLocals)
67 | }
68 |
69 | @Override
70 | public void visitVarInsn(int opcode, int var) {
71 | super.visitVarInsn(opcode, var)
72 | }
73 |
74 | @Override
75 | public void visitJumpInsn(int opcode, Label label) {
76 | super.visitJumpInsn(opcode, label)
77 | }
78 |
79 | @Override
80 | public void visitLookupSwitchInsn(Label label, int[] ints, Label[] labels) {
81 | super.visitLookupSwitchInsn(label, ints, labels)
82 | }
83 |
84 | @Override
85 | public void visitMultiANewArrayInsn(String s, int i) {
86 | super.visitMultiANewArrayInsn(s, i)
87 | }
88 |
89 | @Override
90 | public void visitTableSwitchInsn(int i, int i1, Label label, Label[] labels) {
91 | super.visitTableSwitchInsn(i, i1, label, labels)
92 | }
93 |
94 | @Override
95 | public void visitTryCatchBlock(Label label, Label label1, Label label2, String s) {
96 | super.visitTryCatchBlock(label, label1, label2, s)
97 | }
98 |
99 | @Override
100 | public void visitTypeInsn(int opcode, String s) {
101 | super.visitTypeInsn(opcode, s)
102 | }
103 |
104 | @Override
105 | public void visitLocalVariable(String s, String s1, String s2, Label label, Label label1, int i) {
106 | super.visitLocalVariable(s, s1, s2, label, label1, i)
107 | }
108 |
109 | @Override
110 | public void visitInsn(int opcode) {
111 | super.visitInsn(opcode)
112 | }
113 |
114 | @Override
115 | AnnotationVisitor visitAnnotation(String s, boolean b) {
116 | return super.visitAnnotation(s, b)
117 | }
118 |
119 | @Override
120 | protected void onMethodEnter() {
121 | super.onMethodEnter()
122 | }
123 |
124 | @Override
125 | protected void onMethodExit(int opcode) {
126 | super.onMethodExit(opcode)
127 | }
128 | }
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/analytics/activity/MasAnalyticsMethodCell.groovy:
--------------------------------------------------------------------------------
1 | package com.mas.analytics.activity
2 |
3 | class MasAnalyticsMethodCell {
4 | // 原方法名
5 | String name
6 | // 原方法描述
7 | String desc
8 | // 方法所在的接口或类
9 | String parent
10 | // 采集数据的方法名
11 | String agentName
12 | // 采集数据的方法描述
13 | String agentDesc
14 | // 采集数据的方法参数起始索引( 0:this,1+:普通参数 )
15 | int paramsStart
16 | // 采集数据的方法参数个数
17 | int paramsCount
18 | // 参数类型对应的ASM指令,加载不同类型的参数需要不同的指令
19 | List opcodes
20 |
21 | MasAnalyticsMethodCell(String name, String desc, String parent, String agentName, String agentDesc, int paramsStart, int paramsCount, List opcodes) {
22 | this.name = name
23 | this.desc = desc
24 | this.parent = parent
25 | this.agentName = agentName
26 | this.agentDesc = agentDesc
27 | this.paramsStart = paramsStart
28 | this.paramsCount = paramsCount
29 | this.opcodes = opcodes
30 | }
31 | }
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/analytics/activity/MasAnalyticsUtil.groovy:
--------------------------------------------------------------------------------
1 | package com.mas.analytics.activity
2 |
3 | import org.objectweb.asm.Opcodes
4 |
5 | class MasAnalyticsUtil implements Opcodes {
6 | private static final HashSet targetFragmentClass = new HashSet()
7 | private static final HashSet targetMenuMethodDesc = new HashSet()
8 |
9 | static {
10 | /**
11 | * Menu
12 | */
13 | targetMenuMethodDesc.add("onContextItemSelected(Landroid/view/MenuItem;)Z")
14 | targetMenuMethodDesc.add("onOptionsItemSelected(Landroid/view/MenuItem;)Z")
15 | targetMenuMethodDesc.add("onNavigationItemSelected(Landroid/view/MenuItem;)Z")
16 |
17 | /**
18 | * Fragment
19 | */
20 | targetFragmentClass.add('android/support/v4/app/Fragment')
21 | targetFragmentClass.add('android/support/v4/app/ListFragment')
22 | }
23 |
24 | static boolean isPrivate(int access) {
25 | return (access & ACC_PRIVATE) != 0
26 | }
27 |
28 | static boolean isPublic(int access) {
29 | return (access & ACC_PUBLIC) != 0
30 | }
31 |
32 | static boolean isStatic(int access) {
33 | return (access & ACC_STATIC) != 0
34 | }
35 |
36 | static boolean isTargetMenuMethodDesc(String nameDesc) {
37 | return targetMenuMethodDesc.contains(nameDesc)
38 | }
39 |
40 | static boolean isTargetFragmentClass(String className) {
41 | return targetFragmentClass.contains(className)
42 | }
43 |
44 | static boolean isInstanceOfFragment(String superName) {
45 | return targetFragmentClass.contains(superName)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/log/dynamiclog/ConfigOneWayHashTable.java:
--------------------------------------------------------------------------------
1 | package com.mas.log.dynamiclog;
2 |
3 |
4 | /**
5 | * 创建时间: 2018/9/18
6 | * 类描述: Oneway HaseTable
7 | * https://blog.csdn.net/v_JULY_v/article/details/6256463
8 | *
9 | * @author 秋刀鱼
10 | * @version 1.0
11 | */
12 | public class ConfigOneWayHashTable {
13 | public final static int HASH_OFFSET = 0;
14 | public final static int HASH_A = 1;
15 | public final static int HASH_B = 2;
16 | private volatile static int tableLength;
17 | private static int[] cryptTable = new int[0x500];
18 |
19 | static {
20 | InitCryptTable();
21 | }
22 |
23 | private HaseNode[] hashIndexTable;
24 |
25 | /**
26 | * @param nTableLength
27 | */
28 | private ConfigOneWayHashTable(int nTableLength) {
29 | tableLength = nTableLength;
30 | //初始化hash表
31 | hashIndexTable = new HaseNode[nTableLength];
32 | for (int i = 0; i < nTableLength; i++) {
33 | hashIndexTable[i].nHashA = -1;
34 | hashIndexTable[i].nHashB = -1;
35 | hashIndexTable[i].bExists = false;
36 | }
37 | }
38 |
39 |
40 | /**
41 | * 函数名:InitCryptTable
42 | * 功 能:对哈希索引表预处理
43 | * 返回值:无
44 | */
45 | private static void InitCryptTable() {
46 | int seed = 0x00100001;
47 | int index1;
48 | int index2;
49 | int i;
50 | for (index1 = 0; index1 < 0x100; index1++) {
51 | for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100) {
52 | int temp1, temp2;
53 | seed = (seed * 125 + 3) % 0x2AAAAB;
54 | temp1 = (seed & 0xFFFF) << 0x10;
55 | seed = (seed * 125 + 3) % 0x2AAAAB;
56 | temp2 = (seed & 0xFFFF);
57 | cryptTable[index2] = (temp1 | temp2);
58 | }
59 | }
60 | }
61 |
62 | /**
63 | * 函数名:HashString
64 | * 功 能:求取哈希值
65 | * 返回值:返回hash值
66 | *
67 | * @param lpszString
68 | * @param dwHashType
69 | * @return
70 | */
71 | public static int HashString(String lpszString, int dwHashType) {
72 | int seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
73 | for (int i = 0; i < lpszString.length(); i++) {
74 | char upperChar = Character.toUpperCase(lpszString.charAt(i));
75 | seed1 = cryptTable[(dwHashType << 8) + upperChar] ^ (seed1 + seed2);
76 | seed2 = upperChar + seed1 + seed2 + (seed2 << 5) + 3;
77 | }
78 | return seed1;
79 | }
80 |
81 | /**
82 | * 函数名:Hashed
83 | * 功 能:检测一个字符串是否被hash过
84 | * 返回值:如果存在,返回位置;否则,返回-1
85 | *
86 | * @param lpszString
87 | * @return
88 | */
89 | public HaseNode Hashed(String lpszString) {
90 | //不同的字符串三次hash还会碰撞的几率无限接近于不可能
91 | int nHash = HashString(lpszString, HASH_OFFSET);
92 | int nHashA = HashString(lpszString, HASH_A);
93 | int nHashB = HashString(lpszString, HASH_B);
94 |
95 |
96 | int nHashStart = nHash % tableLength;
97 | int nHashPos = nHashStart;
98 | while (hashIndexTable[nHashPos].bExists) {
99 | if (hashIndexTable[nHashPos].nHashA == nHashA && hashIndexTable[nHashPos].nHashB == nHashB) {
100 | return hashIndexTable[nHashPos];
101 | } else {
102 | nHashPos = (nHashPos + 1) % tableLength;
103 | }
104 | if (nHashPos == nHashStart) {
105 | break;
106 | }
107 |
108 | }
109 | //没有找到
110 | return null;
111 | }
112 |
113 | /**
114 | * @param nHash
115 | * @param nHashA
116 | * @param nHashB
117 | * @return
118 | */
119 | public HaseNode Hashed(int nHash, int nHashA, int nHashB) {
120 | //不同的字符串三次hash还会碰撞的几率无限接近于不可能
121 | int nHashStart = nHash % tableLength;
122 | int nHashPos = nHashStart;
123 | while (hashIndexTable[nHashPos].bExists) {
124 | if (hashIndexTable[nHashPos].nHashA == nHashA && hashIndexTable[nHashPos].nHashB == nHashB) {
125 | return hashIndexTable[nHashPos];
126 | } else {
127 | nHashPos = (nHashPos + 1) % tableLength;
128 | }
129 | if (nHashPos == nHashStart) {
130 | break;
131 | }
132 |
133 | }
134 | //没有找到
135 | return null;
136 | }
137 |
138 | /**
139 | * 函数名:Hash
140 | * 功 能:hash一个字符串
141 | * 返回值:成功,返回true;失败,返回false
142 | *
143 | * @param lpszString
144 | * @return
145 | */
146 | HaseNode Hash(String lpszString, Object data) {
147 | int nHash = HashString(lpszString, HASH_OFFSET);
148 | int nHashA = HashString(lpszString, HASH_A);
149 | int nHashB = HashString(lpszString, HASH_B);
150 | int nHashStart = nHash % tableLength;
151 | int nHashPos = nHashStart;
152 | while (hashIndexTable[nHashPos].bExists) {
153 | nHashPos = (nHashPos + 1) % tableLength;
154 | //一个轮回
155 | if (nHashPos == nHashStart) {
156 | //hash表中没有空余的位置了,无法完成hash
157 | return null;
158 | }
159 | }
160 | hashIndexTable[nHashPos].bExists = true;
161 | hashIndexTable[nHashPos].nHashA = nHashA;
162 | hashIndexTable[nHashPos].nHashB = nHashB;
163 | hashIndexTable[nHashPos].data = data;
164 | return hashIndexTable[nHashPos];
165 | }
166 |
167 | static class Single {
168 | static ConfigOneWayHashTable instance = new ConfigOneWayHashTable(tableLength);
169 | }
170 |
171 | public static class HaseNode {
172 | int nHashA;
173 | int nHashB;
174 | boolean bExists;
175 | Object data;
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/log/mlog/Aops.groovy:
--------------------------------------------------------------------------------
1 | package com.mas.log.mlog
2 |
3 | class Aops {
4 |
5 | public static String rootAops = "[" +
6 |
7 | " {" +
8 | " \"dependent\": \"com.squareup.okhttp3:okhttp\"," +
9 | " \"clazz\": \"okhttp3.OkHttpClient\$Builder\"," +
10 | " \"name\": \"build\"," +
11 | " \"params\": [" +
12 | " \"okhttp3.OkHttpClient\$Builder.build\"" +
13 | " ]" +
14 | " }" +
15 |
16 |
17 | "]"
18 |
19 |
20 | Aops(String clazz, String name, ArrayList args, String dependent) {
21 | this.clazz = clazz
22 | this.name = name
23 | this.params = args
24 | this.dependent = dependent
25 | }
26 | String clazz = ""
27 | String dependent = ""
28 | String name = ""
29 | ArrayList params
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/log/mlog/MAopAnnomationVisitor.groovy:
--------------------------------------------------------------------------------
1 | package com.mas.log.mlog
2 |
3 | import org.objectweb.asm.AnnotationVisitor
4 | import org.objectweb.asm.Opcodes
5 |
6 | class MAopAnnomationVisitor extends AnnotationVisitor implements Opcodes {
7 | ArrayList params
8 |
9 | MAopAnnomationVisitor(int api) {
10 | super(api)
11 | }
12 |
13 | @Override
14 | void visit(String name, Object value) {
15 | if (name.equals("params")) {
16 | params = value
17 | }
18 | }
19 |
20 | @Override
21 | AnnotationVisitor visitArray(String name) {
22 | return getArrayVisitor(name)
23 | }
24 |
25 | AnnotationVisitor getArrayVisitor(String name) {
26 | return new MAopArrayAnnomationVisitor(ASM5, name)
27 | }
28 |
29 | class MAopArrayAnnomationVisitor extends AnnotationVisitor implements Opcodes {
30 | String name
31 |
32 | MAopArrayAnnomationVisitor(int api, String name) {
33 | super(api)
34 | this.name = name
35 | }
36 |
37 | @Override
38 | void visit(String name, Object value) {
39 | if (this.name.equals("params")) {
40 | if (params == null) {
41 | params = new ArrayList<>()
42 | }
43 | params.add(value)
44 | }
45 | }
46 |
47 | }
48 | }
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/plugin/MasExtension.groovy:
--------------------------------------------------------------------------------
1 | package com.mas.plugin
2 |
3 | /**
4 | *
5 | */
6 | class MasExtension {
7 | boolean debug = false
8 | boolean disableJar = false
9 | boolean dylog = false
10 | HashSet exclude = []
11 | HashSet include = []
12 | String maops
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/mas/plugin/MasPlugin.groovy:
--------------------------------------------------------------------------------
1 | package com.mas.plugin
2 |
3 | import com.android.build.gradle.AppExtension
4 | import org.gradle.api.Plugin
5 | import org.gradle.api.Project
6 |
7 | class MasPlugin implements Plugin {
8 |
9 | @Override
10 | void apply(Project project) {
11 | project.extensions.create("monitor", MasExtension)
12 |
13 |
14 | AppExtension appExtension = project.extensions.findByType(AppExtension.class)
15 | appExtension.registerTransform(new MasTransform(project))
16 |
17 | project.afterEvaluate {
18 | Logger.setDebug(project.monitor.debug)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/plugin/src/main/resources/META-INF/gradle-plugins/monitor.properties:
--------------------------------------------------------------------------------
1 | #告诉gradle 自定义plugin的具体实现类
2 | implementation-class=com.mas.plugin.MasPlugin
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/maven-metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.sanyouyu.monitor
4 | monitor
5 | 0.2.2-SNAPSHOT
6 |
7 |
8 | 20190118.073417
9 | 1
10 |
11 | 20190118073417
12 |
13 |
14 |
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/maven-metadata.xml.md5:
--------------------------------------------------------------------------------
1 | 05005103ef4953d72b827f6f2b52f362
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/maven-metadata.xml.sha1:
--------------------------------------------------------------------------------
1 | 481c65e8507be7276ab7ae03b50d557db5a2bb9d
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/monitor-0.2.2-20190118.073417-1.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/monitor-0.2.2-20190118.073417-1.aar
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/monitor-0.2.2-20190118.073417-1.aar.md5:
--------------------------------------------------------------------------------
1 | 1e9047e3a4f1fc158450773b6abfe458
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/monitor-0.2.2-20190118.073417-1.aar.sha1:
--------------------------------------------------------------------------------
1 | 428a85271c422da4bd97625465e6f97430ce6a13
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/monitor-0.2.2-20190118.073417-1.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.sanyouyu.monitor
6 | monitor
7 | 0.2.2-SNAPSHOT
8 | aar
9 |
10 |
11 | com.android.support
12 | appcompat-v7
13 | 26.1.0
14 | compile
15 |
16 |
17 | cc.chenhe
18 | android-lua
19 | 1.0.2
20 | compile
21 |
22 |
23 | org.ow2.asm
24 | asm
25 | 5.1
26 | compile
27 |
28 |
29 | org.apache.commons
30 | commons-lang3
31 | 3.1
32 | compile
33 |
34 |
35 | com.squareup.retrofit2
36 | retrofit
37 | 2.4.0
38 | compile
39 |
40 |
41 | com.tencent
42 | mmkv
43 | 1.0.13
44 | compile
45 |
46 |
47 | com.google.code.gson
48 | gson
49 | 2.8.5
50 | compile
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/monitor-0.2.2-20190118.073417-1.pom.md5:
--------------------------------------------------------------------------------
1 | dc833dc6a302c78fcaad681dd00f005f
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/0.2.2-SNAPSHOT/monitor-0.2.2-20190118.073417-1.pom.sha1:
--------------------------------------------------------------------------------
1 | 48bfbefdcea0434bd1906856050bd0ad64f34bb5
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/maven-metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.sanyouyu.monitor
4 | monitor
5 |
6 |
7 | 0.2.2-SNAPSHOT
8 |
9 | 20190118073417
10 |
11 |
12 |
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/maven-metadata.xml.md5:
--------------------------------------------------------------------------------
1 | d194212d6f8d67c9c7b440fb336f7be8
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/monitor/maven-metadata.xml.sha1:
--------------------------------------------------------------------------------
1 | 4ce1ba37cc59c2574c27358fcc3db675277d84af
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/maven-metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.sanyouyu.monitor
4 | plugin
5 | 0.2.2-SNAPSHOT
6 |
7 |
8 | 20190118.073427
9 | 1
10 |
11 | 20190118073427
12 |
13 |
14 |
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/maven-metadata.xml.md5:
--------------------------------------------------------------------------------
1 | b2001c98d756fedc1d3f02745d2e542b
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/maven-metadata.xml.sha1:
--------------------------------------------------------------------------------
1 | 0d05a4265d52110428353cf7a217d46ec9d002e5
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/plugin-0.2.2-20190118.073427-1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/plugin-0.2.2-20190118.073427-1.jar
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/plugin-0.2.2-20190118.073427-1.jar.md5:
--------------------------------------------------------------------------------
1 | c88b31f71820f432230f178012771f7e
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/plugin-0.2.2-20190118.073427-1.jar.sha1:
--------------------------------------------------------------------------------
1 | 55ef446f93cec28f4e286b053a77f805dfefe831
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/plugin-0.2.2-20190118.073427-1.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.sanyouyu.monitor
6 | plugin
7 | 0.2.2-SNAPSHOT
8 |
9 |
10 | com.android.tools.build
11 | gradle
12 | 3.1.4
13 | runtime
14 |
15 |
16 | com.android.tools.build
17 | transform-api
18 | 1.5.0
19 | runtime
20 |
21 |
22 | org.ow2.asm
23 | asm
24 | 5.1
25 | runtime
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/plugin-0.2.2-20190118.073427-1.pom.md5:
--------------------------------------------------------------------------------
1 | 9405bffcfd999a4db0eba7cf7e9848b9
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/0.2.2-SNAPSHOT/plugin-0.2.2-20190118.073427-1.pom.sha1:
--------------------------------------------------------------------------------
1 | 8e3dfb0c3f847cbe4ff5d58cfb2af5790afd23cf
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/maven-metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.sanyouyu.monitor
4 | plugin
5 |
6 |
7 | 0.2.2-SNAPSHOT
8 |
9 | 20190118073427
10 |
11 |
12 |
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/maven-metadata.xml.md5:
--------------------------------------------------------------------------------
1 | 550056290a3587c3854e674da06e5b4e
--------------------------------------------------------------------------------
/repo/com/sanyouyu/monitor/plugin/maven-metadata.xml.sha1:
--------------------------------------------------------------------------------
1 | 6aef59f4594f5ff5c1f0d2287d97cdcf2d5253fb
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':plugin', ':core', ':flog', ':debug'
2 |
--------------------------------------------------------------------------------