├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── checkstyle-idea.xml ├── codeStyles │ └── Project.xml ├── compiler.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── commons-codec-1.8.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ └── com │ │ └── qiudaoyu │ │ └── service │ │ └── Remote.aidl │ ├── assets │ └── aops.json │ ├── java │ └── com │ │ └── qiudaoyu │ │ ├── service │ │ ├── DataParcelable.java │ │ ├── LocalService.java │ │ └── RemoteService.java │ │ └── test │ │ ├── HttpResult.java │ │ ├── LoginApi.java │ │ ├── MainActivity.java │ │ ├── RetrofitService.java │ │ ├── SecondActivity.java │ │ ├── TabletApplication.java │ │ ├── Test.java │ │ └── ThirdActivity.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_second.xml │ └── activity_third.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── core ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── qiudaoyu │ │ └── monitor │ │ └── ExampleInstrumentedTest.java │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── mcc_mnc_mini.json │ ├── methodconfig.lua │ ├── root.lua │ ├── rootaops.json │ └── test.lua │ ├── java │ ├── com │ │ └── qiudaoyu │ │ │ └── monitor │ │ │ ├── Monitor.java │ │ │ ├── MonitorData.java │ │ │ ├── analysis │ │ │ ├── MasData.java │ │ │ ├── activity │ │ │ │ ├── MasAdapterViewItemTrackProperties.java │ │ │ │ ├── MasDataActivityLifecycleCallbacks.java │ │ │ │ ├── MasDataAutoTrackAppViewScreenUrl.java │ │ │ │ ├── MasDataExceptionHandler.java │ │ │ │ ├── MasDataFragmentTitle.java │ │ │ │ ├── MasDataIgnoreTrackAppViewScreen.java │ │ │ │ ├── MasDataTimer.java │ │ │ │ ├── MasDataViewHelper.java │ │ │ │ ├── MasExpandableListViewItemTrackProperties.java │ │ │ │ └── MasScreenAutoTracker.java │ │ │ ├── battery │ │ │ │ ├── BatteryInfo.java │ │ │ │ └── BatteryMonitor.java │ │ │ ├── cpu │ │ │ │ ├── CpuInfo.java │ │ │ │ ├── CpuMonitor.java │ │ │ │ └── CpuSnapshot.java │ │ │ ├── crash │ │ │ │ ├── CrashInfo.java │ │ │ │ └── CrashMonitor.java │ │ │ ├── memory │ │ │ │ ├── MemMonitor.java │ │ │ │ ├── data │ │ │ │ │ ├── HeapInfo.java │ │ │ │ │ ├── MemInfo.java │ │ │ │ │ ├── Memory.java │ │ │ │ │ ├── PssInfo.java │ │ │ │ │ └── RamInfo.java │ │ │ │ ├── gc │ │ │ │ │ ├── Gc.java │ │ │ │ │ └── GcInfo.java │ │ │ │ └── leak │ │ │ │ │ └── LeakWrapper.java │ │ │ ├── metric │ │ │ │ ├── AbstractSampler.java │ │ │ │ ├── HandlerThreadFactory.java │ │ │ │ ├── MetricInfo.java │ │ │ │ ├── MetricListener.java │ │ │ │ └── MetricMonitor.java │ │ │ ├── network │ │ │ │ ├── NetMonitor.java │ │ │ │ ├── Traffic.java │ │ │ │ └── http │ │ │ │ │ ├── HttpInfo.java │ │ │ │ │ ├── HttpStats.java │ │ │ │ │ └── okhttp │ │ │ │ │ └── NetWorkInterceptor.java │ │ │ ├── storage │ │ │ │ └── Storage.java │ │ │ ├── thread │ │ │ │ └── StackSampler.java │ │ │ ├── ui │ │ │ │ ├── UIMonitor.java │ │ │ │ ├── anr │ │ │ │ │ ├── Anr.java │ │ │ │ │ ├── AnrFileParser.java │ │ │ │ │ └── AnrInfo.java │ │ │ │ ├── blockdetector │ │ │ │ │ ├── BlockInfo.java │ │ │ │ │ └── LooperMonitor.java │ │ │ │ └── fps │ │ │ │ │ ├── Fps.java │ │ │ │ │ └── FpsInfo.java │ │ │ └── utils │ │ │ │ └── MasUtils.java │ │ │ ├── df │ │ │ ├── MMonitor.java │ │ │ ├── config │ │ │ │ └── DFConfigManager.java │ │ │ └── upload │ │ │ │ └── MUploadService.java │ │ │ ├── log │ │ │ ├── MLog.java │ │ │ ├── annotation │ │ │ │ └── IgnoreLog.java │ │ │ ├── dynamiclog │ │ │ │ ├── DLogManager.java │ │ │ │ ├── config │ │ │ │ │ ├── ConfigManager.java │ │ │ │ │ ├── ConfigOneWayHashTable.java │ │ │ │ │ └── MethodConfig.java │ │ │ │ ├── context │ │ │ │ │ ├── MonitorContext.java │ │ │ │ │ └── MonitorContextFactory.java │ │ │ │ ├── lua │ │ │ │ │ ├── LuaConstance.java │ │ │ │ │ ├── LuaRunException.java │ │ │ │ │ ├── LuaUtils.java │ │ │ │ │ └── TestJavaLua.java │ │ │ │ └── pool │ │ │ │ │ └── ObjectPool.java │ │ │ └── mlog │ │ │ │ ├── MAopHandler.java │ │ │ │ ├── MethodValueAopHandler.java │ │ │ │ ├── TrackRunable.java │ │ │ │ └── annotation │ │ │ │ ├── MAop.java │ │ │ │ └── ParentId.java │ │ │ ├── remote │ │ │ ├── Command.java │ │ │ └── RemotCommandService.java │ │ │ ├── upload │ │ │ └── UploadServiceInterface.java │ │ │ └── utils │ │ │ ├── AppUtils.java │ │ │ ├── ContentLisenter.java │ │ │ ├── DeviceUtils.java │ │ │ ├── EmptyUtils.java │ │ │ ├── IoUtil.java │ │ │ ├── JSONUtils.java │ │ │ ├── LocationUtils.java │ │ │ ├── MD5Utils.java │ │ │ ├── MethodValue.java │ │ │ ├── NetWorkUtils.java │ │ │ ├── ProcessUtils.java │ │ │ ├── SharedPreferencesUtils.java │ │ │ ├── ShellUtils.java │ │ │ ├── StacktraceUtil.java │ │ │ ├── ThreadUtils.java │ │ │ └── UUIDGenerator.java │ └── proto │ │ └── config.proto │ └── res │ └── values │ └── strings.xml ├── debug ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── qiudaoyu │ │ └── monitor │ │ └── debug │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── qiudaoyu │ └── monitor │ └── debug │ └── ExampleUnitTest.java ├── flog ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── monitor │ │ └── zmsoft │ │ └── com │ │ └── flog │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── tencent │ │ │ └── mars │ │ │ └── xlog │ │ │ ├── Log.java │ │ │ └── Xlog.java │ ├── jniLibs │ │ ├── armeabi-v7a │ │ │ ├── libmarsxlog.so │ │ │ └── libstlport_shared.so │ │ └── x86_64 │ │ │ ├── libmarsxlog.so │ │ │ └── libstlport_shared.so │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── monitor │ └── zmsoft │ └── com │ └── flog │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin ├── .gitignore ├── build.gradle └── src │ └── main │ ├── groovy │ └── com │ │ └── mas │ │ ├── analytics │ │ └── activity │ │ │ ├── MasAnalyticsClassVisitor.groovy │ │ │ ├── MasAnalyticsDefaultMethodVisitor.groovy │ │ │ ├── MasAnalyticsHookConfig.groovy │ │ │ ├── MasAnalyticsMethodCell.groovy │ │ │ └── MasAnalyticsUtil.groovy │ │ ├── log │ │ ├── dynamiclog │ │ │ ├── ConfigOneWayHashTable.java │ │ │ └── LogClassVisitor.groovy │ │ └── mlog │ │ │ ├── Aops.groovy │ │ │ └── MAopAnnomationVisitor.groovy │ │ └── plugin │ │ ├── Logger.groovy │ │ ├── MasExtension.groovy │ │ ├── MasPlugin.groovy │ │ └── MasTransform.groovy │ └── resources │ └── META-INF │ └── gradle-plugins │ └── monitor.properties ├── repo └── com │ └── sanyouyu │ └── monitor │ ├── monitor │ ├── 0.2.2-SNAPSHOT │ │ ├── maven-metadata.xml │ │ ├── maven-metadata.xml.md5 │ │ ├── maven-metadata.xml.sha1 │ │ ├── monitor-0.2.2-20190118.073417-1.aar │ │ ├── monitor-0.2.2-20190118.073417-1.aar.md5 │ │ ├── monitor-0.2.2-20190118.073417-1.aar.sha1 │ │ ├── monitor-0.2.2-20190118.073417-1.pom │ │ ├── monitor-0.2.2-20190118.073417-1.pom.md5 │ │ └── monitor-0.2.2-20190118.073417-1.pom.sha1 │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 │ └── plugin │ ├── 0.2.2-SNAPSHOT │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ ├── maven-metadata.xml.sha1 │ ├── plugin-0.2.2-20190118.073427-1.jar │ ├── plugin-0.2.2-20190118.073427-1.jar.md5 │ ├── plugin-0.2.2-20190118.073427-1.jar.sha1 │ ├── plugin-0.2.2-20190118.073427-1.pom │ ├── plugin-0.2.2-20190118.073427-1.pom.md5 │ └── plugin-0.2.2-20190118.073427-1.pom.sha1 │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | local.properties 4 | .idea/ 5 | .idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | 13 | 14 | #built application files 15 | *.apk 16 | *.ap_ 17 | 18 | # files for the dex VM 19 | *.dex 20 | 21 | # Java class files 22 | *.class 23 | 24 | # generated files 25 | bin/ 26 | gen/ 27 | out/ 28 | build/ 29 | .idea/ 30 | 31 | # Local configuration file (sdk path, etc) 32 | local.properties 33 | 34 | # Android Studio 35 | *.iml 36 | 37 | # Gradle cache 38 | .gradle 39 | 40 | # Log Files 41 | *.log 42 | /.idea/ 43 | /.gradle/ 44 | /plugin/build/ 45 | /.idea/caches/build_file_checksums.ser 46 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monitor 2 | 数据的价值 3 | APM 4 | 目标: 5 | 6 | 对应用的性能、业务可靠性进行线上的监控和预警 7 | 8 | 采集内容 9 | 10 | 系统指标,应用性能指标,Crash,自定义日志等 11 | 12 | 用户行为 13 | 目标: 14 | 15 | 精细化运营 16 | 17 | 采集内容 18 | 19 | 从用户属性——性别、地域、收入、家庭状况 20 | 21 | 从用户生命周期——注册、活跃、流失 22 | 23 | 从用户行为——功能、内容、产品的喜好等 24 | 25 | 26 | 数据组织形式 27 | 内容+维度 28 | 原图链接:https://my.oschina.net/osccreate/blog/795760 29 | 30 | 31 | 技术手段 32 | 原图链接:https://my.oschina.net/osccreate/blog/795760 33 | 34 | Java层实现功能 35 | 36 | 1.自定义业务数据链路化 37 | 38 | 2.内存指标 39 | 40 | 3.CPU指标 41 | 42 | 4.FPS 指标 43 | 44 | 5.ANR日志 45 | 46 | 6.卡顿检测 47 | 48 | 7.GC日志 49 | 50 | 8.Crash日志 51 | 52 | 9.Http指标数据(暂时只支持OkHttp) 53 | 54 | 10.电量指标 55 | 56 | 11.MAOP,使用注解和配置文件AOP指定方法执行前,执行后,异常插入指定代码的功能 57 | 58 | 59 | 12.Remote下发命令,执行shell和动态执行代码功能 60 | 61 | 62 | 13.交互分析:分析Activity生命周期耗时 63 | 64 | 介绍 65 | https://www.jianshu.com/p/924f90f99257 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'monitor' 3 | def config = rootProject.ext 4 | android { 5 | compileSdkVersion 26 6 | defaultConfig { 7 | applicationId "com.qiudaoyu.monitor" 8 | minSdkVersion 19 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | debug { minifyEnabled false } 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | //默认不扫描引用的依赖,如果在include中包含依赖的完整名称:com.qiudaoyu.monitor:monitor:1.0.2 24 | //先判断是否在include內在判断是否在exclude里 25 | monitor { 26 | //日志 27 | debug true 28 | //jar包完全一致才扫描 29 | include = [] 30 | //依赖和类含有就剔除 31 | exclude = ["cc.chenhe.lib.androidlua", "com.qiudaoyu.monitor.R", "android.support", "qiudaoyu.com.flog"] 32 | 33 | //aop路径 34 | maops "src/main/assets/aops.json" 35 | 36 | } 37 | 38 | dependencies { 39 | implementation commDependencies.supp 40 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 41 | if (config.develop) { 42 | implementation project(':core') 43 | } else { 44 | implementation commDependencies.monitor 45 | } 46 | implementation 'com.squareup.retrofit2:retrofit:2.4.0' 47 | implementation 'com.squareup.retrofit2:converter-gson:2.4.0' 48 | implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0' 49 | implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1' 50 | implementation files('libs/commons-codec-1.8.jar') 51 | } 52 | -------------------------------------------------------------------------------- /app/libs/commons-codec-1.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/libs/commons-codec-1.8.jar -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/aidl/com/qiudaoyu/service/Remote.aidl: -------------------------------------------------------------------------------- 1 | // Remote.aidl 2 | package com.qiudaoyu.service; 3 | 4 | // Declare any non-default types here with import statements 5 | 6 | interface remote { 7 | /** 8 | * Demonstrates some basic types that you can use as parameters 9 | * and return values in AIDL. 10 | */ 11 | void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, 12 | double aDouble, String aString); 13 | int getPid(); 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/assets/aops.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "dependent": "commons-codec-1.8.jar", 4 | "clazz": "com.zmsoft.test.ThirdActivity", 5 | "name": "abc", 6 | "params": [ 7 | "abc", 8 | "1", 9 | "1" 10 | ] 11 | }, 12 | { 13 | "dependent": "com.squareup.okhttp3:okhttp", 14 | "clazz": "okhttp3.OkHttpClient$Builder", 15 | "name": "build", 16 | "params": [ 17 | "okhttp3.OkHttpClient$Builder.build" 18 | ] 19 | } 20 | ] -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/service/DataParcelable.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.service; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * 创建时间: 2018/12/14 8 | * 类描述: 9 | * 10 | * @author 秋刀鱼 11 | * @version 1.0 12 | */ 13 | public class DataParcelable implements Parcelable { 14 | public static final Creator CREATOR = new Creator() { 15 | @Override 16 | public DataParcelable createFromParcel(Parcel in) { 17 | return new DataParcelable(in); 18 | } 19 | 20 | @Override 21 | public DataParcelable[] newArray(int size) { 22 | return new DataParcelable[size]; 23 | } 24 | }; 25 | int a; 26 | int b; 27 | String z; 28 | String d; 29 | 30 | public DataParcelable() { 31 | 32 | } 33 | 34 | protected DataParcelable(Parcel in) { 35 | a = in.readInt(); 36 | b = in.readInt(); 37 | z = in.readString(); 38 | d = in.readString(); 39 | } 40 | 41 | @Override 42 | public int describeContents() { 43 | return 0; 44 | } 45 | 46 | @Override 47 | public void writeToParcel(Parcel dest, int flags) { 48 | dest.writeInt(a); 49 | dest.writeInt(b); 50 | dest.writeString(z); 51 | dest.writeString(d); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/service/LocalService.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.service; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.Binder; 6 | import android.os.IBinder; 7 | import android.support.annotation.Nullable; 8 | import android.util.Log; 9 | 10 | /** 11 | * 创建时间: 2018/12/14 12 | * 类描述: 13 | * 14 | * @author 秋刀鱼 15 | * @version 1.0 16 | */ 17 | public class LocalService extends Service { 18 | private final IBinder mBinder = new LocalBinder(); 19 | 20 | @Nullable 21 | @Override 22 | public IBinder onBind(Intent intent) { 23 | DataParcelable pa = intent.getParcelableExtra("xxxx"); 24 | Log.d("", "onBind pa " + pa); 25 | return mBinder; 26 | } 27 | 28 | @Override 29 | public int onStartCommand(Intent intent, int flags, int startId) { 30 | return super.onStartCommand(intent, flags, startId); 31 | } 32 | 33 | @Override 34 | public void onLowMemory() { 35 | super.onLowMemory(); 36 | } 37 | 38 | @Override 39 | public void onTrimMemory(int level) { 40 | super.onTrimMemory(level); 41 | } 42 | 43 | @Override 44 | public boolean onUnbind(Intent intent) { 45 | return super.onUnbind(intent); 46 | } 47 | 48 | /** 49 | * 50 | * 51 | * 52 | */ 53 | public class LocalBinder extends Binder { 54 | public LocalService getService() { 55 | return LocalService.this; 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/service/RemoteService.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.service; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.IBinder; 6 | import android.util.Log; 7 | 8 | /** 9 | * 创建时间: 2018/12/14 10 | * 类描述: 11 | * 12 | * @author 秋刀鱼 13 | * @version 1.0 14 | */ 15 | public class RemoteService extends Service { 16 | @Override 17 | public IBinder onBind(Intent intent) { 18 | Log.d("intent onBind", "" + intent.getParcelableExtra("abc")); 19 | return null; 20 | } 21 | 22 | @Override 23 | public int onStartCommand(Intent intent, int flags, int startId) { 24 | Log.d("intent onStartCommand", "" + intent.getParcelableExtra("abc")); 25 | return super.onStartCommand(intent, flags, startId); 26 | } 27 | 28 | @Override 29 | public boolean onUnbind(Intent intent) { 30 | return super.onUnbind(intent); 31 | } 32 | 33 | 34 | @Override 35 | public void onLowMemory() { 36 | super.onLowMemory(); 37 | } 38 | 39 | 40 | @Override 41 | public void onTrimMemory(int level) { 42 | super.onTrimMemory(level); 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/test/HttpResult.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.test; 2 | 3 | import android.support.annotation.Keep; 4 | 5 | 6 | /** 7 | * 网络返回对象 8 | * Created by fengyu on 2016/9/28. 9 | */ 10 | @Keep 11 | public class HttpResult { 12 | 13 | private static final int SUCCESS = 1; 14 | 15 | private int code; 16 | 17 | private String errorCode; 18 | private String message; 19 | private String errorMessage; 20 | 21 | public HttpResult() { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/test/LoginApi.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.test; 2 | 3 | import retrofit2.http.GET; 4 | import retrofit2.http.POST; 5 | import retrofit2.http.Query; 6 | 7 | /** 8 | * 创建时间: 2017/8/22 下午2:50 9 | * 类描述: 10 | * 11 | * @author 木棉 12 | */ 13 | public interface LoginApi { 14 | 15 | @POST("?method=com.dfire.boss.center.soa.login.service.IUnifiedLoginClientService.login") 16 | rx.Observable doLogin(@Query("param_str") String param_str, @Query("base_param") String base_param); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/test/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.test; 2 | 3 | import android.app.Activity; 4 | import android.content.ComponentName; 5 | import android.content.Intent; 6 | import android.content.ServiceConnection; 7 | import android.os.Bundle; 8 | import android.os.IBinder; 9 | import android.view.View; 10 | 11 | import com.qiudaoyu.service.DataParcelable; 12 | import com.qiudaoyu.service.LocalService; 13 | import com.qiudaoyu.service.RemoteService; 14 | import com.qiudaoyu.service.DataParcelable; 15 | import com.qiudaoyu.service.LocalService; 16 | import com.qiudaoyu.service.RemoteService; 17 | 18 | import org.json.JSONException; 19 | import org.json.JSONObject; 20 | 21 | import java.util.ArrayList; 22 | import java.util.concurrent.locks.AbstractQueuedSynchronizer; 23 | 24 | public class MainActivity extends Activity { 25 | 26 | 27 | private int xxx = 0; 28 | private LocalService mService; 29 | private boolean mBound; 30 | private ServiceConnection mConnection = new ServiceConnection() { 31 | 32 | @Override 33 | public void onServiceConnected(ComponentName className, 34 | IBinder service) { 35 | // We've bound to LocalService, cast the IBinder and get LocalService instance 36 | LocalService.LocalBinder binder = (LocalService.LocalBinder) service; 37 | mService = binder.getService(); 38 | mBound = true; 39 | } 40 | 41 | @Override 42 | public void onServiceDisconnected(ComponentName arg0) { 43 | mBound = false; 44 | } 45 | }; 46 | 47 | public void main(String[] args) { 48 | JSONObject object = new JSONObject(); 49 | try { 50 | object.put("applyEntityIdList", new ArrayList()); 51 | System.out.print(object.toString()); 52 | } catch (JSONException e) { 53 | e.printStackTrace(); 54 | } 55 | A a = new A(); 56 | a.x = 0; 57 | 58 | } 59 | 60 | @Override 61 | protected void onCreate(Bundle savedInstanceState) { 62 | 63 | super.onCreate(savedInstanceState); 64 | setContentView(R.layout.activity_main); 65 | findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { 66 | @Override 67 | public void onClick(View v) { 68 | startActivity(new Intent(MainActivity.this, SecondActivity.class)); 69 | } 70 | }); 71 | findViewById(R.id.startlocal).setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | } 75 | }); 76 | 77 | findViewById(R.id.startremote).setOnClickListener(new View.OnClickListener() { 78 | @Override 79 | public void onClick(View v) { 80 | Intent intent = new Intent(MainActivity.this, RemoteService.class); 81 | intent.putExtra("abc", new DataParcelable()); 82 | startService(intent); 83 | 84 | } 85 | }); 86 | 87 | findViewById(R.id.startlocal).setOnClickListener(new View.OnClickListener() { 88 | @Override 89 | public void onClick(View v) { 90 | Intent intent = new Intent(MainActivity.this, RemoteService.class); 91 | intent.putExtra("abc", new DataParcelable()); 92 | bindService(intent, new ServiceConnection() { 93 | @Override 94 | public void onServiceConnected(ComponentName name, IBinder service) { 95 | 96 | 97 | } 98 | 99 | @Override 100 | public void onServiceDisconnected(ComponentName name) { 101 | 102 | 103 | } 104 | }, BIND_AUTO_CREATE); 105 | 106 | 107 | } 108 | }); 109 | 110 | 111 | int ii = 0; 112 | switch (ii) { 113 | case 0: 114 | return; 115 | case 1: 116 | return; 117 | case 2: 118 | return; 119 | case 3: 120 | return; 121 | } 122 | 123 | } 124 | 125 | protected int abc(int a, int b, int c) { 126 | return a + b + c; 127 | } 128 | 129 | protected int zzz(int a, int b, int c) { 130 | return a + b + c; 131 | } 132 | 133 | class A { 134 | private int x = xxx; 135 | 136 | private void test(String a) { 137 | 138 | } 139 | 140 | private void test2(String a) { 141 | try { 142 | test(a); 143 | } catch (Exception e) { 144 | test(a); 145 | } finally { 146 | test(a); 147 | } 148 | } 149 | 150 | } 151 | 152 | class aa extends AbstractQueuedSynchronizer { 153 | 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/test/RetrofitService.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.test; 2 | 3 | 4 | import com.google.gson.Gson; 5 | 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import okhttp3.OkHttpClient; 10 | import okhttp3.logging.HttpLoggingInterceptor; 11 | import retrofit2.Retrofit; 12 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 13 | import retrofit2.converter.gson.GsonConverterFactory; 14 | 15 | 16 | public class RetrofitService { 17 | 18 | /** 19 | * 连接超时时间 20 | * 5s 21 | */ 22 | public static final int CONNECT_TIMEOUT_MILLIS = 6 * 1000; 23 | /** 24 | * 响应超时时间 25 | * 5s 26 | */ 27 | public static final int READ_TIMEOUT_MILLIS = 6 * 1000; 28 | private final static Object mRetrofitLock = new Object(); 29 | 30 | private static Retrofit sRetrofit; 31 | private static OkHttpClient sOkHttpClient; 32 | private static ConcurrentHashMap, Object> mCache = new ConcurrentHashMap(); 33 | 34 | public static Retrofit getRetrofit() { 35 | if (sRetrofit == null) { 36 | synchronized (mRetrofitLock) { 37 | if (sRetrofit == null) { 38 | OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder(); 39 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 40 | clientBuilder 41 | .connectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) 42 | .readTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 43 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 44 | clientBuilder.addInterceptor(httpLoggingInterceptor); 45 | sOkHttpClient = clientBuilder.build(); 46 | sRetrofit = new Retrofit.Builder().client(sOkHttpClient) 47 | .baseUrl("http://www.baidu.com") 48 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 49 | .addConverterFactory(GsonConverterFactory.create(new Gson())) 50 | .build(); 51 | } 52 | } 53 | } 54 | return sRetrofit; 55 | } 56 | 57 | 58 | @SuppressWarnings("unchecked") 59 | public static T getProxy(Class tClass) { 60 | return getRetrofit().create(tClass); 61 | } 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/test/SecondActivity.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.test; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import java.util.ArrayList; 13 | 14 | public class SecondActivity extends Activity { 15 | 16 | 17 | private int xxx = 0; 18 | 19 | public void main(String[] args) { 20 | JSONObject object = new JSONObject(); 21 | try { 22 | object.put("applyEntityIdList", new ArrayList()); 23 | System.out.print(object.toString()); 24 | } catch (JSONException e) { 25 | e.printStackTrace(); 26 | } 27 | A a = new A(); 28 | a.x = 0; 29 | a.test(); 30 | } 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_main); 37 | ((TextView) findViewById(R.id.btn)).setText("hello second "); 38 | findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { 39 | @Override 40 | public void onClick(View v) { 41 | startActivity(new Intent(SecondActivity.this, ThirdActivity.class)); 42 | } 43 | }); 44 | } 45 | 46 | protected int abc(int a, int b, int c) { 47 | return a + b + c; 48 | } 49 | 50 | protected int zzz(int a, int b, int c) { 51 | return a + b + c; 52 | } 53 | 54 | class A { 55 | private int x = xxx; 56 | 57 | private void test() { 58 | 59 | } 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/test/TabletApplication.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.test; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.support.annotation.Keep; 6 | import android.util.Log; 7 | 8 | import com.qiudaoyu.monitor.MonitorData; 9 | import com.qiudaoyu.monitor.df.MMonitor; 10 | import com.qiudaoyu.monitor.log.annotation.IgnoreLog; 11 | import com.qiudaoyu.monitor.log.mlog.MethodValueAopHandler; 12 | 13 | /** 14 | * 创建时间: 2017/8/14 下午2:12 15 | * 类描述: 16 | * 17 | * @author 木棉 18 | */ 19 | @Keep 20 | @IgnoreLog 21 | public class TabletApplication extends Application { 22 | 23 | @SuppressLint("MissingPermission") 24 | @Override 25 | public void onCreate() { 26 | super.onCreate(); 27 | 28 | // if (AppUtils.isMainProcess(this, BuildConfig.APPLICATION_ID)) { 29 | MMonitor.Builder.newBuilder().context(this) 30 | .appInfo("com.qiudaoyu.kds", BuildConfig.VERSION_NAME) 31 | .appKey("200020", "guce5uq2mbp0t7rn1eg7yrnd7gt0yg4e") 32 | .uploadService(MMonitor.TEST_URL, MMonitor.TEST_PROT, "/sdcard/kds/upload", (short) 200) 33 | .isDebugEnalbe(BuildConfig.DEBUG) 34 | .mAopHandler(new MethodValueAopHandler() { 35 | 36 | @Override 37 | public void vBefore(String[] params, Object classOrInstance, Object[] args) { 38 | 39 | } 40 | 41 | @Override 42 | public void vAfter(int mode, Object returnValue, String[] params, Object classOrInstance, Object[] args) { 43 | Log.e("after", "" + params.toString() + " " + returnValue + " "); 44 | } 45 | 46 | @Override 47 | public void vException(Object exception, String[] params, Object classOrInstance, Object[] args) { 48 | 49 | 50 | } 51 | }) 52 | .MLog(BuildConfig.DEBUG, "KDS", null) 53 | .install(new int[]{ 54 | MonitorData.TYPE_METRIC_ANR, 55 | MonitorData.TYPE_METRIC_BLOCK, 56 | MonitorData.TYPE_METRIC_GC, 57 | MonitorData.TYPE_METRIC_HTTP, 58 | MonitorData.TYPE_APP_START, 59 | MonitorData.TYPE_APP_END, 60 | MonitorData.TYPE_APP_CLICK, 61 | MonitorData.TYPE_APP_VIEW, 62 | }) 63 | .build(); 64 | 65 | //开始监控 66 | MMonitor.getInstance().start(); 67 | 68 | 69 | //登录之后设置userId和entityId 70 | MMonitor.getInstance().setUserId("000001", "abcdefghigk"); 71 | //} 72 | 73 | } 74 | 75 | 76 | @Override 77 | public void onLowMemory() { 78 | super.onLowMemory(); 79 | MMonitor.getInstance().onLowMemory(); 80 | 81 | } 82 | 83 | @Override 84 | public void onTrimMemory(int level) { 85 | super.onTrimMemory(level); 86 | MMonitor.getInstance().onTrimMemory(level); 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiudaoyu/test/Test.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.test; 2 | 3 | import com.qiudaoyu.monitor.log.mlog.annotation.MAop; 4 | import com.qiudaoyu.monitor.log.mlog.annotation.MAop; 5 | 6 | /** 7 | * 创建时间: 2018/11/29 8 | * 类描述: 9 | * 10 | * @author 秋刀鱼 11 | * @version 1.0 12 | */ 13 | public class Test { 14 | 15 | @MAop 16 | private long test1(long x, long x1, long x2, long x3) { 17 | testl(x); 18 | testl(x1); 19 | testl(x2); 20 | return x2; 21 | } 22 | 23 | private long testl(long x) { 24 | 25 | return x; 26 | } 27 | 28 | private int testi(int x) { 29 | 30 | return x; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 17 | 18 | 25 | 26 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_second.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_third.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 24 | 25 | 26 | 33 | 34 | 35 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyouyugan/Mas/82a3be64f5414672b82bbb527121eada9d7082ee/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Monitor 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | ext { 4 | // 统一项目环境 5 | develop = true 6 | 7 | deployVersion = "0.2.2-SNAPSHOT" 8 | 9 | version = "0.2.2-SNAPSHOT" 10 | 11 | commDependencies = [ 12 | supp : 'com.android.support:appcompat-v7:26.1.0', 13 | gradle : 'com.android.tools.build:gradle:3.1.4', 14 | transform: 'com.android.tools.build:transform-api:1.5.0', 15 | asm : 'org.ow2.asm:asm:5.1', 16 | protobuf : 'com.google.protobuf:protobuf-lite:3.0.0', 17 | lua : 'cc.chenhe:android-lua:1.0.2', 18 | commons : 'org.apache.commons:commons-lang3:3.1', 19 | retrofit : 'com.squareup.retrofit2:retrofit:2.4.0', 20 | monitor : "com.sanyouyu.monitor:monitor:${version}", 21 | mmkv : 'com.tencent:mmkv:1.0.13', 22 | gson : 'com.google.code.gson:gson:2.8.5' 23 | ] 24 | 25 | } 26 | 27 | repositories { 28 | maven { 29 | url uri('./repo') 30 | } 31 | 32 | maven { 33 | url 'https://maven.aliyun.com/repository/google/' 34 | } 35 | maven { 36 | url 'https://maven.aliyun.com/repository/jcenter/' 37 | } 38 | maven { 39 | url 'https://maven.aliyun.com/repository/central/' 40 | } 41 | 42 | } 43 | 44 | dependencies { 45 | classpath 'com.android.tools.build:gradle:3.1.4' 46 | classpath "com.sanyouyu.monitor:plugin:${rootProject.ext.version}" 47 | classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5' 48 | // NOTE: Do not place your application dependencies here; they belong 49 | // in the individual module build.gradle files 50 | } 51 | } 52 | 53 | allprojects { 54 | repositories { 55 | 56 | maven { 57 | url uri('./repo') 58 | } 59 | 60 | maven { 61 | url 'https://maven.aliyun.com/repository/google/' 62 | } 63 | maven { 64 | url 'https://maven.aliyun.com/repository/jcenter/' 65 | } 66 | maven { 67 | url 'https://maven.aliyun.com/repository/central/' 68 | } 69 | 70 | 71 | } 72 | } 73 | 74 | 75 | task clean(type: Delete) { 76 | delete rootProject.buildDir 77 | rootProject.task(":app:uploadArchives") 78 | } 79 | 80 | //发布插件和jar包 81 | task Adeploy(dependsOn: ["clean", ":core:uploadArchives", ":plugin:uploadArchives"]) { 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /core/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | def config = rootProject.ext 2 | apply plugin: 'com.android.library' 3 | apply plugin: 'com.google.protobuf' 4 | apply plugin: 'maven' 5 | android { 6 | compileSdkVersion 26 7 | 8 | 9 | 10 | defaultConfig { 11 | minSdkVersion 14 12 | targetSdkVersion 26 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | 19 | 20 | buildTypes { 21 | debug { 22 | buildConfigField "String", "SDK_VER", "\"${config.version}\"" 23 | 24 | minifyEnabled false 25 | } 26 | release { 27 | buildConfigField "String", "SDK_VER", "\"${config.version}\"" 28 | 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | } 32 | } 33 | sourceSets { 34 | main { 35 | java { 36 | srcDirs 'src/main/java' 37 | } 38 | proto { 39 | srcDirs 'src/main/java/proto' 40 | } 41 | } 42 | } 43 | 44 | } 45 | 46 | //android studio 使用 pb 47 | //https://www.jianshu.com/p/df200894f5da 48 | protobuf { 49 | protoc { 50 | // You still need protoc like in the non-Android case 51 | artifact = 'com.google.protobuf:protoc:3.0.0' 52 | } 53 | plugins { 54 | javalite { 55 | // The codegen for lite comes as a separate artifact 56 | artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0' 57 | } 58 | } 59 | generateProtoTasks { 60 | all().each { task -> 61 | task.builtins { 62 | // In most cases you don't need the full Java output 63 | // if you use the lite output. 64 | remove java 65 | } 66 | task.plugins { 67 | javalite {} 68 | } 69 | } 70 | } 71 | } 72 | 73 | dependencies { 74 | implementation fileTree(dir: 'libs', include: ['*.jar']) 75 | // You need to depend on the lite runtime library, not protobuf-java 76 | compileOnly commDependencies.protobuf 77 | implementation commDependencies.supp 78 | implementation commDependencies.lua 79 | implementation commDependencies.asm 80 | implementation commDependencies.commons 81 | implementation commDependencies.retrofit 82 | implementation commDependencies.mmkv 83 | implementation commDependencies.gson 84 | 85 | } 86 | 87 | uploadArchives { 88 | repositories.mavenDeployer { 89 | 90 | repository(url:uri('../repo')) { 91 | 92 | } 93 | 94 | snapshotRepository(url:uri('../repo')) { 95 | 96 | } 97 | pom.project { 98 | groupId "com.sanyouyu.monitor" 99 | artifactId "monitor" 100 | if (config.develop) { 101 | version "${config.deployVersion}" 102 | } else { 103 | version "${config.version}" 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /core/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 | -------------------------------------------------------------------------------- /core/src/androidTest/java/com/qiudaoyu/monitor/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor; 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.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /core/src/main/assets/methodconfig.lua: -------------------------------------------------------------------------------- 1 | --- 2 | --- Generated by EmmyLua(https://github.com/EmmyLua) 3 | --- Created by yushen. 4 | --- DateTime: 2018/9/19 14:14 5 | --- 6 | --[[ 7 | loadstring 定义values 8 | 方便luastate复用 9 | --]] 10 | 11 | local values = { 12 | data = {}, 13 | args = {}, 14 | before = function(argMaps) 15 | 16 | end, 17 | exception = function(exception) 18 | 19 | end, 20 | after = function(returnValue) 21 | 22 | end 23 | } 24 | 25 | --https://blog.csdn.net/lang523493505/article/details/51218912 26 | stack[(#stack + 1)] = values 27 | values = nil 28 | 29 | --------------------- 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /core/src/main/assets/root.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | loadstring 定义values 3 | 方便luastate复用 4 | --]] 5 | 6 | stack = {} 7 | 8 | function callTopFunc(funcName, value2) 9 | local ok, value = pcall(stack[#stack][funcName], value2) 10 | if ok then 11 | return 0, value 12 | else 13 | return -1, value 14 | end 15 | end 16 | 17 | function releaseTop() 18 | stack[#stack].args = nil 19 | stack[#stack].init = nil 20 | stack[#stack].before = nil 21 | stack[#stack].exception = nil 22 | stack[#stack].after = nil 23 | stack[#stack].values = nil 24 | stack[#stack].data = nil 25 | table.remove(stack) 26 | end 27 | 28 | function getTopData() 29 | return stack[#stack].data 30 | end 31 | 32 | function initTop (map) 33 | local top = stack[#stack] 34 | for k, v in pairs(map) do 35 | top.args[k] = v 36 | end 37 | end 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /core/src/main/assets/rootaops.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "dependent": "commons-codec-1.8.jar", 4 | "clazz": "com.zmsoft.test.ThirdActivity", 5 | "name": "abc", 6 | "params": [ 7 | "abc", 8 | "1", 9 | "1" 10 | ] 11 | }, 12 | { 13 | "dependent": "com.squareup.okhttp3:okhttp", 14 | "clazz": "okhttp3.OkHttpClient$Builder", 15 | "name": "build", 16 | "params": [ 17 | "okhttp3.OkHttpClient$Builder.build" 18 | ] 19 | } 20 | ] -------------------------------------------------------------------------------- /core/src/main/assets/test.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | loadstring 定义values 3 | 方便luastate复用 4 | --]] 5 | 6 | local values = { 7 | data = {}, 8 | args = {}, 9 | before = function(tv) 10 | log = luajava.bindClass("android.util.Log") 11 | log:e("xx", "from lua before 1") 12 | if (tv) then 13 | log:e("xx", "" .. tv:toString()) 14 | else 15 | log:e("xx", "tv 为 null") 16 | end 17 | tv:setText("from lua before"); 18 | log:e("xx", "from lua before 2") 19 | return "before" 20 | end, 21 | exception = function(exception) 22 | 23 | end, 24 | after = function(returnValue) 25 | 26 | end 27 | } 28 | 29 | --https://blog.csdn.net/lang523493505/article/details/51218912 30 | stack[(#stack + 1)] = values 31 | values = nil 32 | 33 | --------------------- 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/MonitorData.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor; 2 | 3 | /** 4 | * 创建时间: 2018/12/11 5 | * 类描述: 6 | * 7 | * @author 秋刀鱼 8 | * @version 1.0 9 | */ 10 | public class MonitorData { 11 | 12 | //metric 13 | public static final int TYPE_METRIC_MEM = 0; 14 | public static final int TYPE_METRIC_CPU = 1; 15 | public static final int TYPE_METRIC_FPS = 2; 16 | public static final int TYPE_METRIC_ANR = 3; 17 | public static final int TYPE_METRIC_BLOCK = 4; 18 | public static final int TYPE_METRIC_GC = 5; 19 | public static final int TYPE_METRIC_HTTP = 6; 20 | public static final int TYPE_METRIC_BATTERY = 7; 21 | public static final int TYPE_METRIC_CRASH = 8; 22 | 23 | //activity 24 | public static final int TYPE_APP_START = 1008; 25 | public static final int TYPE_APP_END = 1009; 26 | public static final int TYPE_APP_CLICK = 10010; 27 | public static final int TYPE_APP_VIEW = 10011; 28 | 29 | public static String getTpye(int mType) { 30 | switch (mType) { 31 | case TYPE_METRIC_MEM: 32 | return "TYPE_METRIC_MEM"; 33 | case TYPE_METRIC_CPU: 34 | return "TYPE_METRIC_CPU"; 35 | case TYPE_METRIC_FPS: 36 | return "TYPE_METRIC_FPS"; 37 | case TYPE_METRIC_ANR: 38 | return "TYPE_METRIC_ANR"; 39 | case TYPE_METRIC_BLOCK: 40 | return "TYPE_METRIC_BLOCK"; 41 | case TYPE_METRIC_GC: 42 | return "TYPE_METRIC_GC"; 43 | case TYPE_METRIC_HTTP: 44 | return "TYPE_METRIC_HTTP"; 45 | case TYPE_METRIC_BATTERY: 46 | return "TYPE_METRIC_BATTERY"; 47 | case TYPE_METRIC_CRASH: 48 | return "TYPE_METRIC_CRASH"; 49 | } 50 | return ""; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasAdapterViewItemTrackProperties.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | /** 7 | * Created by qiudaoyu on 2016/11/30 8 | * 获取 ListView、GridView position 位置 Item 的 properties 9 | */ 10 | 11 | public interface MasAdapterViewItemTrackProperties { 12 | /** 13 | * 点击 position 处 item 的扩展属性 14 | * 15 | * @param position 当前 item 所在位置 16 | * @return JSONObject 17 | * @throws JSONException JSON 异常 18 | */ 19 | JSONObject getItemTrackProperties(int position) throws JSONException; 20 | } -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasDataAutoTrackAppViewScreenUrl.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Inherited; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * 11 | */ 12 | 13 | @Inherited 14 | @Target({ElementType.TYPE}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface MasDataAutoTrackAppViewScreenUrl { 17 | String url() default ""; 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasDataExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 2 | 3 | 4 | import com.qiudaoyu.monitor.analysis.MasData; 5 | import com.qiudaoyu.monitor.log.MLog; 6 | 7 | import org.json.JSONObject; 8 | 9 | import java.io.PrintWriter; 10 | import java.io.StringWriter; 11 | import java.io.Writer; 12 | 13 | public class MasDataExceptionHandler implements Thread.UncaughtExceptionHandler { 14 | private static final int SLEEP_TIMEOUT_MS = 3000; 15 | 16 | private static MasDataExceptionHandler sInstance; 17 | private final Thread.UncaughtExceptionHandler mDefaultExceptionHandler; 18 | 19 | private MasDataExceptionHandler() { 20 | mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); 21 | Thread.setDefaultUncaughtExceptionHandler(this); 22 | } 23 | 24 | public static MasDataExceptionHandler getsInstance() { 25 | return Single.sInstace; 26 | } 27 | 28 | @Override 29 | public void uncaughtException(final Thread t, final Throwable e) { 30 | // Only one worker thread - giving priority to storing the event first and then flush 31 | 32 | try { 33 | final JSONObject messageProp = new JSONObject(); 34 | MasDataTimer.getInstance().cancleTimerTask(); 35 | try { 36 | Writer writer = new StringWriter(); 37 | PrintWriter printWriter = new PrintWriter(writer); 38 | e.printStackTrace(printWriter); 39 | Throwable cause = e.getCause(); 40 | while (cause != null) { 41 | cause.printStackTrace(printWriter); 42 | cause = cause.getCause(); 43 | } 44 | printWriter.close(); 45 | String result = writer.toString(); 46 | messageProp.put("$app_crashed_reason", result); 47 | } catch (Exception ex) { 48 | ex.printStackTrace(); 49 | } 50 | MasData.getInstance().trackEvent(MasData.EVENT_APPCRASH, messageProp); 51 | } catch (Exception e1) { 52 | MLog.e("MasE", "", e); 53 | } 54 | 55 | 56 | if (mDefaultExceptionHandler != null) { 57 | try { 58 | Thread.sleep(SLEEP_TIMEOUT_MS); 59 | } catch (InterruptedException e1) { 60 | } 61 | mDefaultExceptionHandler.uncaughtException(t, e); 62 | } else { 63 | killProcessAndExit(); 64 | } 65 | } 66 | 67 | private void killProcessAndExit() { 68 | try { 69 | Thread.sleep(SLEEP_TIMEOUT_MS); 70 | } catch (InterruptedException e1) { 71 | e1.printStackTrace(); 72 | } 73 | android.os.Process.killProcess(android.os.Process.myPid()); 74 | System.exit(10); 75 | } 76 | 77 | static class Single { 78 | static MasDataExceptionHandler sInstace; 79 | 80 | static { 81 | sInstace = new MasDataExceptionHandler(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasDataFragmentTitle.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 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 | @Target({ElementType.TYPE, ElementType.METHOD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | 11 | public @interface MasDataFragmentTitle { 12 | String title() default ""; 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasDataIgnoreTrackAppViewScreen.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 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 | * Created by 王灼洲 on 2017/1/5 10 | */ 11 | 12 | @Target({ElementType.TYPE, ElementType.METHOD}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface MasDataIgnoreTrackAppViewScreen { 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasDataTimer.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 2 | 3 | import java.util.Timer; 4 | import java.util.TimerTask; 5 | 6 | public class MasDataTimer { 7 | 8 | private Timer mTimer; 9 | private TimerTask mTimerTask; 10 | private static MasDataTimer instance; 11 | private final int TIME_INTERVAL = 1000; 12 | 13 | public static MasDataTimer getInstance() { 14 | if (instance == null) { 15 | instance = new MasDataTimer(); 16 | } 17 | return instance; 18 | } 19 | 20 | private MasDataTimer() { 21 | } 22 | 23 | /** 24 | * start a timer task 25 | * @param runnable 26 | */ 27 | public void timer(final Runnable runnable) { 28 | mTimerTask = new TimerTask() { 29 | @Override 30 | public void run() { 31 | runnable.run(); 32 | } 33 | }; 34 | if (mTimer == null) { 35 | mTimer = new Timer(); 36 | mTimer.schedule(mTimerTask, 0, TIME_INTERVAL); 37 | } else { 38 | mTimer.schedule(mTimerTask, 0, TIME_INTERVAL); 39 | } 40 | } 41 | 42 | /** 43 | * cancel timer task 44 | */ 45 | public void cancleTimerTask() { 46 | if (mTimerTask != null) { 47 | mTimerTask.cancel(); 48 | mTimerTask = null; 49 | } 50 | 51 | if (mTimer != null) { 52 | mTimer.cancel(); 53 | mTimer.purge(); 54 | mTimer = null; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasExpandableListViewItemTrackProperties.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | /** 7 | * Created by qiudaoyu on 2016/11/30 8 | * ExpandableListView 9 | */ 10 | 11 | public interface MasExpandableListViewItemTrackProperties { 12 | /** 13 | * 点击 groupPosition、childPosition 处 item 的扩展属性 14 | * @param groupPosition 15 | * @param childPosition 16 | * @return 17 | * @throws JSONException 18 | */ 19 | JSONObject getChildItemTrackProperties(int groupPosition, int childPosition) throws JSONException; 20 | 21 | /** 22 | * 点击 groupPosition 处 item 的扩展属性 23 | * @param groupPosition 24 | * @return 25 | * @throws JSONException 26 | */ 27 | JSONObject getGroupItemTrackProperties(int groupPosition) throws JSONException; 28 | } -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/activity/MasScreenAutoTracker.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.activity; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | /** 7 | * Created by qiudaoyu on 16/9/22 8 | */ 9 | public interface MasScreenAutoTracker { 10 | /** 11 | * 返回当前页面的Url 12 | * 用作下个页面的referrer 13 | * @return String 14 | */ 15 | String getScreenUrl(); 16 | 17 | /** 18 | * 返回自定义属性集合 19 | * 我们内置了一个属性:$screen_name,代表当前页面名称, 默认情况下,该属性会采集当前Activity的CanonicalName,即: 20 | * activity.getClass().getCanonicalName(), 如果想自定义页面名称, 可以在Map里put该key进行覆盖。 21 | * 注意:screen_name的前面必须要要加"$"符号 22 | * 23 | * @return JSONObject 24 | * @throws JSONException JSONException 25 | */ 26 | JSONObject getTrackProperties() throws JSONException; 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/battery/BatteryInfo.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.battery; 2 | 3 | import android.os.BatteryManager; 4 | 5 | /** 6 | * Created by kysonchao on 2017/11/22. 7 | */ 8 | public class BatteryInfo { 9 | public static final BatteryInfo INVALID = new BatteryInfo(); 10 | 11 | // int类型,状态,定义值是BatteryManager.BATTERY_STATUS_XXX / 正在充电、充满等等 12 | public int status; 13 | // int类型,健康,定义值是BatteryManager.BATTERY_HEALTH_XXX。 14 | public int health; 15 | // boolean类型 16 | public boolean present; 17 | // int类型,电池剩余容量 18 | public int level; 19 | //int类型,电池最大值。通常为100。 20 | public int scale; 21 | //int类型,连接的电源插座,定义值是BatteryManager.BATTERY_PLUGGED_XXX。 22 | public int plugged; 23 | //int类型,电压 mV 24 | public int voltage; 25 | //int类型,温度,0.1度单位。例如 表示197的时候,意思为19.7度。 26 | public int temperature; 27 | //String类型,电池类型,例如,Li-ion等等。 28 | public String technology; 29 | 30 | public long time; 31 | public static final String SPILT = "\r\n"; 32 | 33 | @Override 34 | public String toString() { 35 | return new StringBuilder().append("statusSummary: ").append(getDisplayStatus()).append(SPILT) 36 | .append("health: ").append(getDisplayHealth()).append(SPILT) 37 | .append("present: ").append(present).append(SPILT) 38 | .append("level: ").append(level).append(SPILT) 39 | .append("scale: ").append(scale).append(SPILT) 40 | .append("plugged: ").append(getDisplayPlugged()).append(SPILT) 41 | .append("voltage: ").append(voltage / 1000.0).append(SPILT) 42 | .append("temperature: ").append(temperature / 10.0).append(SPILT) 43 | .append("technology: ").append(technology) 44 | .toString(); 45 | } 46 | 47 | public String getDisplayStatus() { 48 | switch (status) { 49 | case BatteryManager.BATTERY_STATUS_CHARGING: 50 | // 充电状态 51 | return "charging"; 52 | case BatteryManager.BATTERY_STATUS_DISCHARGING: 53 | // 放电中 54 | return "discharging"; 55 | case BatteryManager.BATTERY_STATUS_NOT_CHARGING: 56 | // 未充电 57 | return "not charging"; 58 | case BatteryManager.BATTERY_STATUS_FULL: 59 | // 电池满 60 | return "full"; 61 | case BatteryManager.BATTERY_STATUS_UNKNOWN: 62 | default: 63 | return "unknown"; 64 | } 65 | } 66 | 67 | public String getDisplayHealth() { 68 | switch (health) { 69 | case BatteryManager.BATTERY_HEALTH_GOOD: 70 | // 良好 71 | return "good"; 72 | case BatteryManager.BATTERY_HEALTH_OVERHEAT: 73 | //过热 74 | return "overheat"; 75 | case BatteryManager.BATTERY_HEALTH_DEAD: 76 | //没电 77 | return "dead"; 78 | case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: 79 | //过电压 80 | return "voltage"; 81 | case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: 82 | return "unspecified failure"; 83 | case BatteryManager.BATTERY_HEALTH_COLD: 84 | return "cold"; 85 | case BatteryManager.BATTERY_HEALTH_UNKNOWN: 86 | default: 87 | return "unknown"; 88 | } 89 | } 90 | 91 | public String getDisplayPlugged() { 92 | switch (plugged) { 93 | case BatteryManager.BATTERY_PLUGGED_AC: 94 | // 充电器 95 | return "ac"; 96 | case BatteryManager.BATTERY_PLUGGED_USB: 97 | // USB 98 | return "usb"; 99 | case BatteryManager.BATTERY_PLUGGED_WIRELESS: 100 | // wireless 101 | return "wireless"; 102 | default: 103 | return "unknown"; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/battery/BatteryMonitor.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.battery; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.IntentFilter; 7 | import android.os.BatteryManager; 8 | 9 | import com.qiudaoyu.monitor.analysis.metric.MetricListener; 10 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor; 11 | import com.qiudaoyu.monitor.MonitorData; 12 | import com.qiudaoyu.monitor.analysis.metric.MetricListener; 13 | import com.qiudaoyu.monitor.analysis.metric.MetricMonitor; 14 | import com.qiudaoyu.monitor.log.MLog; 15 | 16 | /** 17 | * 创建时间: 2018/12/2 18 | * 类描述: 19 | * 20 | * @author 秋刀鱼 21 | * @version 1.0 22 | */ 23 | public class BatteryMonitor extends MetricMonitor { 24 | private BroadcastReceiver batteryReceiver = new BroadcastReceiver() { 25 | 26 | @Override 27 | public void onReceive(Context context, Intent batteryInfoIntent) { 28 | BatteryInfo batteryInfo = new BatteryInfo(); 29 | batteryInfo.status = batteryInfoIntent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager 30 | .BATTERY_STATUS_UNKNOWN); 31 | batteryInfo.health = batteryInfoIntent.getIntExtra(BatteryManager.EXTRA_HEALTH, BatteryManager 32 | .BATTERY_HEALTH_UNKNOWN); 33 | batteryInfo.present = batteryInfoIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false); 34 | batteryInfo.level = batteryInfoIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); 35 | batteryInfo.scale = batteryInfoIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 0); 36 | batteryInfo.plugged = batteryInfoIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); 37 | batteryInfo.voltage = batteryInfoIntent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0); 38 | batteryInfo.temperature = batteryInfoIntent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0); 39 | batteryInfo.technology = batteryInfoIntent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY); 40 | batteryInfo.time = System.currentTimeMillis(); 41 | metricData(MonitorData.TYPE_METRIC_BATTERY, batteryInfo); 42 | } 43 | }; 44 | 45 | public BatteryMonitor(MetricListener metricListener) { 46 | super(metricListener); 47 | } 48 | 49 | /** 50 | * 获取电池信息 51 | * 52 | * @param context 53 | * @return 获取电池信息 54 | */ 55 | public void start(Context context) { 56 | try { 57 | IntentFilter BATTERY_INTENT_FILTER = new IntentFilter(); 58 | BATTERY_INTENT_FILTER.addAction(Intent.ACTION_BATTERY_CHANGED); 59 | BATTERY_INTENT_FILTER.addAction(Intent.ACTION_BATTERY_LOW); 60 | BATTERY_INTENT_FILTER.addAction(Intent.ACTION_BATTERY_OKAY); 61 | context.registerReceiver(batteryReceiver, BATTERY_INTENT_FILTER); 62 | } catch (Throwable e) { 63 | MLog.e("Battry", "fail ", e); 64 | } 65 | } 66 | 67 | public void stop(Context context) { 68 | if (context != null) { 69 | try { 70 | context.unregisterReceiver(batteryReceiver); 71 | } catch (Exception e) { 72 | } 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/cpu/CpuInfo.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.cpu; 2 | 3 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo; 4 | import com.qiudaoyu.monitor.analysis.metric.MetricInfo; 5 | import com.qiudaoyu.monitor.log.MLog; 6 | 7 | import java.io.Serializable; 8 | import java.util.Locale; 9 | 10 | /** 11 | * Description: 12 | * 一个sample时间段内 13 | * 总的cpu使用率 14 | * app的cpu使用率 15 | * 用户进程cpu使用率 16 | * 系统进程cpu使用率 17 | * io等待时间占比 18 | 19 | */ 20 | public class CpuInfo extends MetricInfo implements Serializable{ 21 | public static final CpuInfo INVALID = new CpuInfo(); 22 | // 总的cpu使用率(user + system+io+其他) 23 | public double totalUseRatio; 24 | // app的cpu使用率 25 | public double appCpuRatio; 26 | // 用户进程cpu使用率 27 | public double userCpuRatio; 28 | // 系统进程cpu使用率 29 | public double sysCpuRatio; 30 | // io等待时间占比 31 | public double ioWaitRatio; 32 | //采样开始时间 33 | private long startTime; 34 | //采样结束时间 35 | private long endTime; 36 | 37 | public CpuInfo(double totalUseRatio, double appCpuRatio, double userCpuRatio, double sysCpuRatio, double 38 | ioWaitRatio, long startTime, long endTime) { 39 | this.totalUseRatio = totalUseRatio; 40 | this.appCpuRatio = appCpuRatio; 41 | this.userCpuRatio = userCpuRatio; 42 | this.sysCpuRatio = sysCpuRatio; 43 | this.ioWaitRatio = ioWaitRatio; 44 | this.startTime = startTime; 45 | this.endTime = endTime; 46 | } 47 | 48 | public CpuInfo() { 49 | } 50 | 51 | 52 | public static CpuInfo accumlate(CpuSnapshot startSnapshot, long startTime, CpuSnapshot endSnapshot, long endTime) { 53 | 54 | float totalTime = (endSnapshot.total - startSnapshot.total) * 1.0f; 55 | if (totalTime <= 0) { 56 | MLog.d("cpu", "totalTime must greater than 0"); 57 | return CpuInfo.INVALID; 58 | } 59 | long idleTime = endSnapshot.idle - startSnapshot.idle; 60 | double totalRatio = (totalTime - idleTime) / totalTime; 61 | double appRatio = (endSnapshot.app - startSnapshot.app) / totalTime; 62 | double userRatio = (endSnapshot.user - startSnapshot.user) / totalTime; 63 | double systemRatio = (endSnapshot.system - startSnapshot.system) / totalTime; 64 | double ioWaitRatio = (endSnapshot.ioWait - startSnapshot.ioWait) / totalTime; 65 | if (!isValidRatios(totalRatio, appRatio, userRatio, systemRatio, ioWaitRatio)) { 66 | MLog.d("cpu", "not valid ratio"); 67 | return CpuInfo.INVALID; 68 | } 69 | return new CpuInfo(totalRatio, appRatio, userRatio, systemRatio, ioWaitRatio, startTime, endTime); 70 | } 71 | 72 | private static boolean isValidRatios(Double... ratios) { 73 | for (double ratio : ratios) { 74 | if (ratio < 0 || ratio > 1) { 75 | return false; 76 | } 77 | } 78 | return true; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return "app:" + 84 | String.format(Locale.US, "%.1f", appCpuRatio * 100f) + 85 | "% , total:" + 86 | String.format(Locale.US, "%.1f", totalUseRatio * 100f) + 87 | "% , user:" + 88 | String.format(Locale.US, "%.1f", userCpuRatio * 100f) + 89 | "% , system:" + 90 | String.format(Locale.US, "%.1f", sysCpuRatio * 100f) + 91 | "% , iowait:" + 92 | String.format(Locale.US, "%.1f", ioWaitRatio * 100f) + "%"; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/cpu/CpuMonitor.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.cpu; 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 | 11 | /** 12 | * 创建时间: 2018/12/11 13 | * 类描述: 14 | * 15 | * @author 秋刀鱼 16 | * @version 1.0 17 | */ 18 | public class CpuMonitor extends MetricMonitor { 19 | 20 | private Thread workDamondThread; 21 | 22 | private volatile int waitTime = 500; 23 | 24 | public CpuMonitor(MetricListener metricListener) { 25 | super(metricListener); 26 | } 27 | 28 | @Override 29 | public void start(final Context context) { 30 | if (isInstalled(MonitorData.TYPE_METRIC_MEM)) { 31 | workDamondThread = new Thread(new Runnable() { 32 | @Override 33 | public void run() { 34 | synchronized (workDamondThread) { 35 | while (!Thread.interrupted()) { 36 | long start = System.currentTimeMillis(); 37 | CpuSnapshot cpuSnapshot = CpuSnapshot.getCpuUsage(); 38 | try { 39 | workDamondThread.wait(waitTime); 40 | } catch (InterruptedException e) { 41 | } 42 | long end = System.currentTimeMillis(); 43 | CpuSnapshot cpuSnapshotEnd = CpuSnapshot.getCpuUsage(); 44 | //收集mem数据 45 | metricData(MonitorData.TYPE_METRIC_CPU, CpuInfo.accumlate(cpuSnapshot, start, cpuSnapshotEnd, end)); 46 | } 47 | } 48 | } 49 | }); 50 | workDamondThread.start(); 51 | } 52 | } 53 | 54 | @Override 55 | public void stop(Context context) { 56 | if (workDamondThread != null) { 57 | synchronized (workDamondThread) { 58 | workDamondThread.notify(); 59 | } 60 | workDamondThread.interrupt(); 61 | workDamondThread = null; 62 | } 63 | } 64 | 65 | @Override 66 | public void notifyWork() { 67 | if (workDamondThread != null) { 68 | synchronized (workDamondThread) { 69 | workDamondThread.notify(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /core/src/main/java/com/qiudaoyu/monitor/analysis/crash/CrashInfo.java: -------------------------------------------------------------------------------- 1 | package com.qiudaoyu.monitor.analysis.crash; 2 | 3 | import com.qiudaoyu.monitor.utils.StacktraceUtil; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | 9 | /** 10 | */ 11 | public class CrashInfo implements Serializable { 12 | public static CrashInfo INVALID = new CrashInfo(); 13 | public long timestampMillis; 14 | public String threadName; 15 | public String threadState; 16 | public String threadGroupName; 17 | public boolean threadIsDaemon; 18 | public boolean threadIsAlive; 19 | public boolean threadIsInterrupted; 20 | public String throwableMessage; 21 | public List 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 | --------------------------------------------------------------------------------