koom 源码分析之 koom-monitor-base
生活随笔
收集整理的這篇文章主要介紹了
koom 源码分析之 koom-monitor-base
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.LoopMonitor開啟單獨線程每隔1s監聽一次
abstract class LoopMonitor<C> : Monitor<C>(), Callable<LoopMonitor.LoopState> {companion object {private const val DEFAULT_LOOP_INTERVAL = 1000L}//是否停止了//https://www.jianshu.com/p/3963e64e7fe7//在kotlin中沒有volatile關鍵字,但是有@Volatile注解,@Volatile//@Volatile將把JVM支持字段標記為volatileprivate var mIsLoopStopped = true//單獨線程private val mLoopRunnable = object : Runnable {override fun run() {//如果call返回Terminate則停止if (call() == LoopState.Terminate) {return}if (mIsLoopStopped) {return}getLoopHandler().removeCallbacks(this)getLoopHandler().postDelayed(this, getLoopInterval())}}//開啟open fun startLoop(clearQueue: Boolean = true,postAtFront: Boolean = false,delayMillis: Long = 0L) {if (clearQueue) getLoopHandler().removeCallbacks(mLoopRunnable)if (postAtFront) {getLoopHandler().postAtFrontOfQueue(mLoopRunnable)} else {getLoopHandler().postDelayed(mLoopRunnable, delayMillis)}mIsLoopStopped = false}//停止open fun stopLoop() {mIsLoopStopped = truegetLoopHandler().removeCallbacks(mLoopRunnable)}//1s中protected open fun getLoopInterval(): Long {return DEFAULT_LOOP_INTERVAL}//一個開啟消息循環線程的Handlerprotected open fun getLoopHandler(): Handler {return commonConfig.loopHandlerInvoker()}sealed class LoopState {//兩個狀態Continueobject Continue : LoopState()//兩個狀態Terminateobject Terminate : LoopState()} }2.LoopThread開辟單獨線程
//用object 修飾的類為靜態類,里面的方法和變量都為靜態的。 internal object LoopThread : HandlerThread("LoopThread", THREAD_PRIORITY_BACKGROUND) {init {start()}internal val LOOP_HANDLER = Handler(LoopThread.looper) }3.CommonConfig默認文件夾,SharedPreferences,log,加載so,線程池等
class CommonConfig private constructor(// MonitorManager common propertiesval application: Application,// Custom FileManager or sharedPreferencesval rootFileInvoker: (String) -> File,//默認文件夾val sharedPreferencesInvoker: (String) -> SharedPreferences,val sharedPreferencesKeysInvoker: (SharedPreferences) -> Set<String>,// MonitorBuildConfig common propertiesinternal val debugMode: Boolean,internal val versionNameInvoker: () -> String,internal val logger: Logger, //koom的Loggerinternal val log: Log, //koom的Log// toolboxinternal val loadSoInvoker: (String) -> Unit, //加載sointernal val executorServiceInvoker: (() -> ExecutorService)?,//線程池// For LooperMonitorinternal val loopHandlerInvoker: () -> Handler//后臺線程handler ) {class Builder {private lateinit var mApplication: Applicationprivate var mDebugMode = trueprivate lateinit var mVersionNameInvoker: () -> Stringprivate lateinit var mDeviceIdInvoker: (() -> String)private var mRootFileInvoker: ((String) -> File)? = nullprivate var mSharedPreferencesInvoker: ((String) -> SharedPreferences)? = nullprivate var mSharedPreferencesKeysInvoker: ((SharedPreferences) -> Set<String>)? = nullprivate var mLogger: Logger? = nullprivate var mLog: Log? = nullprivate var mLoadSoInvoker: ((String) -> Unit)? = nullprivate var mExecutorServiceInvoker: (() -> ExecutorService)? = nullprivate var mLoopHandlerInvoker: (() -> Handler)? = nullfun setApplication(application: Application) = apply {mApplication = application}fun setDebugMode(debugMode: Boolean) = apply {mDebugMode = debugMode}fun setVersionNameInvoker(versionNameInvoker: () -> String) = apply {mVersionNameInvoker = versionNameInvoker}fun setRootFileInvoker(rootFileInvoker: (String) -> File) = apply {mRootFileInvoker = rootFileInvoker}fun setSharedPreferencesInvoker(sharedPreferencesInvoker: (String) -> SharedPreferences) = apply {mSharedPreferencesInvoker = sharedPreferencesInvoker}fun setSharedPreferencesKeysInvoker(sharedPreferencesKeysInvoker: (SharedPreferences) -> Set<String>) = apply {mSharedPreferencesKeysInvoker = sharedPreferencesKeysInvoker}fun setLoadSoInvoker(LoadSoInvoker: (String) -> Unit) = apply {mLoadSoInvoker = LoadSoInvoker}fun setLogger(logger: Logger) = apply {mLogger = logger}fun setLog(log: Log) = apply {mLog = log}fun setExecutorServiceInvoker(executorServiceInvoker: () -> ExecutorService) = apply {mExecutorServiceInvoker = executorServiceInvoker}fun setLoopHandlerInvoker(loopHandlerInvoker: () -> Handler) = apply {mLoopHandlerInvoker = loopHandlerInvoker}fun build(): CommonConfig = CommonConfig(application = mApplication,debugMode = mDebugMode,versionNameInvoker = mVersionNameInvoker,rootFileInvoker = mRootFileInvoker ?: {//默認文件夾//https://blog.csdn.net/Kelaker/article/details/80471352//內部存儲:應用文件目錄:$applicationDir/files//外部存儲:應用文件目錄:$applicationDir/files,// 通過Context.getExternalFilesDir(String type),type為空字符串時獲取。val rootDir = runCatching { mApplication.getExternalFilesDir("") }.getOrNull()//rootDir不為null了,則parent為rootDir,否則為mApplication.filesDirFile(rootDir ?: mApplication.filesDir, "performance/$it")//這里 todo $it是啥.apply { mkdirs() }},sharedPreferencesInvoker = mSharedPreferencesInvoker ?: {mApplication.getSharedPreferences("performance", Context.MODE_PRIVATE)//默認performance},sharedPreferencesKeysInvoker = mSharedPreferencesKeysInvoker ?: { it.all.keys },logger = mLogger ?: object : Logger {},log = mLog ?: object : Log {},loadSoInvoker = mLoadSoInvoker ?: { System.loadLibrary(it) },executorServiceInvoker = mExecutorServiceInvoker,loopHandlerInvoker = mLoopHandlerInvoker ?: { LoopThread.LOOP_HANDLER }//默認LoopThread.LOOP_HANDLER)} }4.Monitor 一個CommonConfig公共配置,一個單獨配置
abstract class Monitor<C> {//一個CommonConfig公共配置private var _commonConfig: CommonConfig? = nullprotected val commonConfig: CommonConfigget() = _commonConfig!!//一個c,單獨配置private var _monitorConfig: C? = nullprotected val monitorConfig: Cget() = _monitorConfig!!//是否初始化了open var isInitialized = falseprotected inline fun throwIfNotInitialized(onDebug: () -> Unit = {throw RuntimeException("Monitor is not initialized")},onRelease: () -> Unit) {if (isInitialized) {return}if (MonitorBuildConfig.DEBUG) {onDebug()} else {onRelease()}}protected fun Boolean.syncToInitialized() = apply {isInitialized = this && isInitialized}open fun init(commonConfig: CommonConfig, monitorConfig: C) {_commonConfig = commonConfig_monitorConfig = monitorConfigisInitialized = true}open fun getLogParams(): Map<String, Any> {return mapOf("${javaClass.simpleName.decapitalize()}ingEnabled" to isInitialized)} }5.Monitor_Application.kt
//currentActivity 當前activity
// isForeground 是否前臺
// lifecycleEventObservers 監聽進程狀態
// registerActivityLifecycleCallbacks 監聽activity狀態 + 進程狀態
//currentActivity 當前activity
// isForeground 是否前臺
// lifecycleEventObservers 監聽進程狀態
// registerActivityLifecycleCallbacks 監聽activity狀態 + 進程狀態
private var _currentActivity: WeakReference<Activity>? = null
val Application.currentActivity: Activity?get() = _currentActivity?.get()private var _isForeground = false
val Application.isForegroundget() = _isForegroundprivate val _lifecycleEventObservers = CopyOnWriteArrayList<LifecycleEventObserver>()
fun Application.registerProcessLifecycleObserver(observer: LifecycleEventObserver) =_lifecycleEventObservers.add(observer)fun Application.unregisterProcessLifecycleObserver(observer: LifecycleEventObserver) =_lifecycleEventObservers.remove(observer)internal fun registerApplicationExtension() {getApplication().registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {private fun updateCurrentActivityWeakRef(activity: Activity) {_currentActivity = if (_currentActivity?.get() == activity) {_currentActivity} else {WeakReference(activity)}}override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {updateCurrentActivityWeakRef(activity)}override fun onActivityStarted(activity: Activity) {}override fun onActivityResumed(activity: Activity) {updateCurrentActivityWeakRef(activity)}override fun onActivityPaused(activity: Activity) {}override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}override fun onActivityStopped(activity: Activity) {}override fun onActivityDestroyed(activity: Activity) {}})ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleEventObserver {override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {when (event) {Lifecycle.Event.ON_START -> _isForeground = trueLifecycle.Event.ON_STOP -> _isForeground = falseelse -> Unit}for (lifecycleEventObserver in _lifecycleEventObservers) {lifecycleEventObserver.onStateChanged(source, event)}}})
}
6.Monitor_File.kt壓縮文件,readFirstLine讀取文件第一行
/*** When compressing, only the last-level file name is retained, and the path is not retained.* Files with the same name under different paths will be overwritten* 壓縮時只保留最后一級文件名,不保留路徑。 不同路徑下的同名文件會被覆蓋*/ const val ZIP_LAST_PATH_NAME = -1/*** Keep original directory structure when compressing* 壓縮時保持原始目錄結構*/ const val ZIP_FULL_PATH_NAME = 0fun File.zipTo(zipFile: File, zipType: Int = ZIP_LAST_PATH_NAME) {if (isFile) {arrayListOf(this).zipTo(zipFile.absolutePath, zipType)} else if (isDirectory) {//導入folder里的文件arrayListOf<File>().apply { buildSrcFileList(this) }.zipTo(zipFile.absolutePath, zipType)} }fun List<File>.zipTo(zipFilePath: String, zipType: Int = ZIP_LAST_PATH_NAME) {ZipOutputStream(FileOutputStream(zipFilePath)).use { out ->for (file in this) {//this指的是List<File>val filePath = file.absolutePathif (zipType == ZIP_LAST_PATH_NAME) {ZipEntry(filePath.substring(filePath.lastIndexOf("/") + 1))} else {ZipEntry(filePath)}.also {//it知道是ZipEntryout.putNextEntry(it)}//out是ZipOutputStreamFileInputStream(file).use { it.copyTo(out) }}} }fun File.readFirstLine(): String? {useLines { return it.firstOrNull() } }//遍歷文件夾將文件加入到srcFileList里 private fun File.buildSrcFileList(srcFileList: MutableList<File>) {for (file in listFiles().orEmpty()) {if (file.isDirectory) {file.buildSrcFileList(srcFileList)} else if (file.isFile) {srcFileList.add(file)}} }7.Monitor_Process.kt 是否主進程,進程名,是否arm64
enum class Abi {ARMEABI_V7A,ARM64_V8A,UNKNOWN }@Volatile private var mCurrentAbi: Abi = Abi.UNKNOWN private var mProcessName: String? = nullfun isMainProcess() = MonitorManager.getApplication().packageName == getProcessName()fun getProcessName(): String? {return mProcessName?: getProcessNameByAms()?.also { mProcessName = it }?: getProcessNameByProc()?.also { mProcessName = it } }fun isArm64(): Boolean {return getCurrentAbi() == Abi.ARM64_V8A }fun getCurrentAbi(): Abi {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return Abi.ARMEABI_V7Aif (mCurrentAbi != Abi.UNKNOWN) return mCurrentAbi// Check system api"dalvik.system.VMRuntime".toClass()//todo?.callStaticMethod<Any>("getRuntime")?.run { callMethod<Boolean>("is64Bit") }?.also {mCurrentAbi = if (it) Abi.ARM64_V8A else Abi.ARMEABI_V7Areturn mCurrentAbi}// Check address size"sun.misc.Unsafe".toClass()//todo?.callStaticMethod<Any>("getUnsafe")?.run { callMethod<Int>("addressSize") }?.also {mCurrentAbi = if (it == 8) Abi.ARM64_V8A else Abi.ARMEABI_V7Areturn mCurrentAbi}// Check so pathtry {getApplication().applicationInfo.nativeLibraryDir.contains("arm64").also { mCurrentAbi = if (it) Abi.ARM64_V8A else Abi.ARMEABI_V7A }} catch (e: Throwable) {e.printStackTrace()}return mCurrentAbi }private fun getProcessNameByProc(): String? {return try {File("/proc/" + Process.myPid() + "/" + "cmdline").readText().trim(' ', '\u0000')} catch (e: Exception) {e.printStackTrace()null} }private fun getProcessNameByAms(): String? {try {val activityManager = MonitorManager.getApplication().getSystemService(Context.ACTIVITY_SERVICE)as ActivityManagerval appProcessList = activityManager.runningAppProcessesfor (processInfo in appProcessList.orEmpty()) {if (processInfo.pid == Process.myPid()) {return processInfo.processName}}} catch (e: Exception) {e.printStackTrace()}return null }8.Monitor_Reflect.kt 反射獲取或者設置類的靜態/非靜態成員變量,調用靜態/非靜態成員方法
fun String.toClass(): Class<*>? {return runCatching { Class.forName(this) }.getOrNull() }fun <T> Class<*>.getStaticFiledValue(filedName: String): T? {return runCatching {return@runCatching getFiledQuietly(filedName)?.get(null) as T?}.getOrNull() }fun <T> Any.getFiledValue(filedName: String): T? {return runCatching {return@runCatching this::class.java.getFiledQuietly(filedName)?.get(this) as T?}.getOrNull() }fun Class<*>.setStaticFiledValue(filedName: String, filedValue: Any?) {runCatching {return@runCatching getFiledQuietly(filedName)?.set(null, filedValue)} }fun Any.setFiledValue(filedName: String, filedValue: Any?) {runCatching {return@runCatching this::class.java.getFiledQuietly(filedName)?.set(this, filedValue)} }fun Class<*>.getFiledQuietly(filedName: String): Field? {return runCatching {var targetClass: Class<*>? = thiswhile (targetClass != Any::class.java) {//targetField是Field類型val targetField = runCatching { targetClass?.getDeclaredField(filedName) }.getOrNull()if (targetField != null) {return@runCatching targetField.also { it.isAccessible = true }} else {targetClass = targetClass?.superclass}}return@runCatching null}.getOrNull() }fun <T> Any.callMethod(methodName: String,parameterTypes: Array<Class<*>>? = null,args: Array<Any>? = null ): T? {return runCatching {val method = this::class.java.getDeclaredMethodQuietly(methodName, parameterTypes)?: return@runCatching nullreturn@runCatching if (args == null) {method.invoke(this)} else {method.invoke(this, *args)} as T?}.getOrNull() }fun <T> Class<*>.callStaticMethod(methodName: String,parameterTypes: Array<Class<*>>? = null,args: Array<Any>? = null ): T? {return runCatching {val method = this.getDeclaredMethodQuietly(methodName, parameterTypes)?: return@runCatching nullreturn@runCatching if (args == null) {method.invoke(null)} else {method.invoke(null, *args)} as T?}.getOrNull() }fun Class<*>.getDeclaredMethodQuietly(filedName: String,parameterTypes: Array<Class<*>>? = null ): Method? {return runCatching {var targetClass: Class<*>? = thiswhile (targetClass != Any::class.java) {val targetMethod = runCatching {if (parameterTypes == null) {targetClass?.getDeclaredMethod(filedName)} else {targetClass?.getDeclaredMethod(filedName, *parameterTypes)}}.getOrNull()if (targetMethod != null) {return@runCatching targetMethod.also { it.isAccessible = true }} else {targetClass = targetClass?.superclass}}return@runCatching null}.getOrNull() }9.Monitor_SharedPreferences.kt獲取sharedPreferences的所有key
//獲取sharedPreferences的所有key val SharedPreferences.allKeys: Set<String>get() = MonitorManager.commonConfig.sharedPreferencesKeysInvoker(this)10.Monitor_So.kt加載so,判斷是否支持64位
private const val TAG = "MonitorSo"@Deprecated("Deprecated", ReplaceWith("loadSoQuietly(soName)")) fun loadSo(soName: String) = MonitorManager.commonConfig.loadSoInvoker(soName)//加載so fun loadSoQuietly(soName: String): Boolean = runCatching {MonitorManager.commonConfig.loadSoInvoker(soName)//soreturn@runCatching true }.onFailure {it.printStackTrace()MonitorLog.e(TAG, it.message + "\n" + Log.getStackTraceString(it)) }.getOrElse { false }//是否支持64 fun isSupportArm64(): Boolean {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {return false}return supportedABIs().contains("arm64-v8a") }//ok private fun supportedABIs(): Array<String> {return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP&& Build.SUPPORTED_ABIS.isNotEmpty()) {Build.SUPPORTED_ABIS} else if (!Build.CPU_ABI2.isNullOrEmpty()) {//todoarrayOf(Build.CPU_ABI, Build.CPU_ABI2)} else {//todoarrayOf(Build.CPU_ABI)} }11.Monitor_System.kt 獲取mRamTotalSize總的RAM容量,mCpuCoreCount cpu核心數,mCpuMaxFreq cpu最大頻率,MemInfo內存信息,JavaHeap堆內存信息,ProcessStatus進程所占內存信息
//https://my.oschina.net/u/4592355/blog/5004330 //VSS - Virtual Set Size (用處不大)虛擬耗用內存(包含共享庫占用的全部內存,以及分配但未使用內存)。 // 其大小還包括了可能不在RAM中的內存(比如雖然malloc分配了空間,但尚未寫入)。 // VSS 很少被用于判斷一個進程的真實內存使用量。 //RSS - Resident Set Size (用處不大) //實際使用物理內存(包含共享庫占用的全部內存)。但是RSS還是可能會造成誤導,因為它僅僅表示該進程所使用的所有共享庫的大小, // 它不管有多少個進程使用該共享庫,該共享庫僅被加載到內存一次。所以RSS并不能準確反映單進程的內存占用情況。 //PSS - Proportional Set Size (僅供參考) //實際使用的物理內存(比例分配共享庫占用的內存,按照進程數等比例劃分)。 //例如:如果有三個進程都使用了一個共享庫,共占用了30頁內存。那么PSS將認為每個進程分別占用該共享庫10頁的大小。 //PSS是非常有用的數據,因為系統中所有進程的PSS都相加的話,就剛好反映了系統中的 總共占用的內存。 // 而當一個進程被銷毀之后, 其占用的共享庫那部分比例的PSS,將會再次按比例分配給余下使用該庫的進程。 //這樣PSS可能會造成一點的誤導,因為當一個進程被銷毀后, PSS不能準確地表示返回給全局系統的內存。 //USS - Unique Set Size (非常有用) //進程獨自占用的物理內存(不包含共享庫占用的內存)。USS是非常非常有用的數據,因為它反映了運行一個特定進程真實的邊際成本 // (增量成本)。當一個進程被銷毀后,USS是真實返回給系統的內存。當進程中存在一個可疑的內存泄露時,USS是最佳觀察數據。private val VSS_REGEX = "VmSize:\\s*(\\d+)\\s*kB".toRegex()//todo private val RSS_REGEX = "VmRSS:\\s*(\\d+)\\s*kB".toRegex()//todo private val THREADS_REGEX = "Threads:\\s*(\\d+)\\s*".toRegex()private val MEM_TOTAL_REGEX = "MemTotal:\\s*(\\d+)\\s*kB".toRegex() private val MEM_FREE_REGEX = "MemFree:\\s*(\\d+)\\s*kB".toRegex() private val MEM_AVA_REGEX = "MemAvailable:\\s*(\\d+)\\s*kB".toRegex() //https://www.jianshu.com/p/9edfe9d5eb34 //ion disp:display 相關的ion模塊內存占用 ion是離子 todo //cma usage:cma模塊占用 private val MEM_CMA_REGEX = "CmaTotal:\\s*(\\d+)\\s*kB".toRegex()//todo private val MEM_ION_REGEX = "ION_heap:\\s*(\\d+)\\s*kB".toRegex()//todoprivate var mCpuCoreCount: Int? = null private var mRamTotalSize: Long? = null private var mCpuMaxFreq: Double? = null@JvmField var lastProcessStatus = ProcessStatus()@JvmField var lastMemInfo = MemInfo()@JvmField var lastJavaHeap = JavaHeap()fun getRamTotalSize(): Long {return mRamTotalSize ?: File("/proc/meminfo").useLines {it.forEach { line ->if (line.contains("MemTotal")) {val array = line.split("\\s+".toRegex()).toTypedArray()return@useLines array.getOrElse(1) { "0" }.toLong() shl 10}}return@useLines 0L}.also { mRamTotalSize = it } }fun getRamAvailableSize(context: Context): Long {val memoryInfo = ActivityManager.MemoryInfo()(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).also { it.getMemoryInfo(memoryInfo) }return memoryInfo.availMem }fun getCpuCoreCount(): Int {return mCpuCoreCount?: runCatching {File("/sys/devices/system/cpu/").listFiles { pathname -> Pattern.matches("cpu[0-9]+", pathname.name) }?.size?: 0}.getOrDefault(Runtime.getRuntime().availableProcessors()).also { mCpuCoreCount = it } }fun getCpuMaxFreq(): Double {return mCpuMaxFreq?: runCatching {(File("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq").readFirstLine()?.trim()?.toDouble()?: 0.0) / 1000}.getOrDefault(0.0).also { mCpuMaxFreq = it } }/*** Get Pss/Vss/etc.*/ fun getProcessStatus(): ProcessStatus {val processStatus = ProcessStatus()runCatching {File("/proc/self/status").useLines {it.forEach { line ->//讀取文件的每行//如果都不為0的時候返回信息if (processStatus.vssKbSize != 0L && processStatus.rssKbSize != 0L&& processStatus.threadsCount != 0L) {lastProcessStatus = processStatusreturn processStatus}when {line.startsWith("VmSize") -> processStatus.vssKbSize = VSS_REGEX.matchValue(line)line.startsWith("VmRSS") -> processStatus.rssKbSize = RSS_REGEX.matchValue(line)line.startsWith("Threads") ->processStatus.threadsCount = THREADS_REGEX.matchValue(line)}}}}lastProcessStatus = processStatusreturn processStatus }fun getMemoryInfo(): MemInfo {val memInfo = MemInfo()File("/proc/meminfo").useLines {it.forEach { line ->when {line.startsWith("MemTotal") -> memInfo.totalInKb = MEM_TOTAL_REGEX.matchValue(line)line.startsWith("MemFree") -> memInfo.freeInKb = MEM_FREE_REGEX.matchValue(line)line.startsWith("MemAvailable") -> memInfo.availableInKb = MEM_AVA_REGEX.matchValue(line)line.startsWith("CmaTotal") -> memInfo.cmaTotal = MEM_CMA_REGEX.matchValue(line)line.startsWith("ION_heap") -> memInfo.IONHeap = MEM_ION_REGEX.matchValue(line)}}}memInfo.rate = 1.0f * memInfo.availableInKb / memInfo.totalInKblastMemInfo = memInforeturn memInfo }fun getJavaHeap(): JavaHeap {val javaHeap = JavaHeap()javaHeap.max = Runtime.getRuntime().maxMemory()javaHeap.total = Runtime.getRuntime().totalMemory()javaHeap.free = Runtime.getRuntime().freeMemory()javaHeap.used = javaHeap.total - javaHeap.freejavaHeap.rate = 1.0f * javaHeap.used / javaHeap.maxlastJavaHeap = javaHeapreturn javaHeap }class ProcessStatus {@JvmFieldvar vssKbSize: Long = 0@JvmFieldvar rssKbSize: Long = 0@JvmFieldvar threadsCount: Long = 0 }class MemInfo(@JvmFieldvar totalInKb: Long = 0,@JvmFieldvar freeInKb: Long = 0,@JvmFieldvar availableInKb: Long = 0,@JvmFieldvar IONHeap: Long = 0,//todo@JvmFieldvar cmaTotal: Long = 0,//todo@JvmFieldvar rate: Float = 0f )//https://blog.csdn.net/qijingwang/article/details/86162648 //JvmField在這里是生成get set方法,在伴生對象里,用于消除調用Companion class JavaHeap(@JvmFieldvar max: Long = 0,@JvmFieldvar total: Long = 0,@JvmFieldvar free: Long = 0,@JvmFieldvar used: Long = 0,@JvmFieldvar rate: Float = 0f )private fun Regex.matchValue(s: String) = matchEntire(s.trim())?.groupValues?.getOrNull(1)?.toLong() ?: 0L12.Monitor_Thread.kt 在主線程/線程池里執行代碼
internal val mainHandler = Handler(Looper.getMainLooper())//異步 fun async(delayMills: Long = 0L, block: () -> Unit) {if (delayMills != 0L) {mainHandler.postDelayed({MonitorManager.commonConfig.executorServiceInvoker?.invoke()?.submit(block)?: thread { block() }}, delayMills)} else {//調用線程池運行block,如果為空則創建thread創建blockMonitorManager.commonConfig.executorServiceInvoker?.invoke()?.submit(block)?: thread { block() }} }fun postOnMainThread(delayMills: Long = 0L, block: () -> Unit) {mainHandler.postDelayed(block, delayMills) }fun runOnMainThread(block: () -> Unit) {if (Looper.myLooper() == Looper.getMainLooper()) {block()} else {mainHandler.post(block)} }fun postOnMainThread(delay: Long = 0L, runnable: Runnable) {mainHandler.postDelayed(runnable, delay) }fun removeCallbacks(runnable: Runnable) {mainHandler.removeCallbacks(runnable) }13.MonitorBuildConfig 獲取一些信息debug,version_name,rom
object MonitorBuildConfig {@JvmStaticval DEBUG by lazy { MonitorManager.commonConfig.debugMode }@JvmStaticval VERSION_NAME by lazy { MonitorManager.commonConfig.versionNameInvoker() }@JvmStaticval ROM by lazy { Build.MANUFACTURER.toUpperCase().let { if (it == "HUAWEI") "EMUI" else "OTHER"} } }14.MonitorConfig 里邊有個builder,生成相應的MonitorConfig
abstract class MonitorConfig<M> {interface Builder<C: MonitorConfig<*>> {fun build(): C} }15.MonitorLog 本地打log
//MonitorLog本地打log object MonitorLog {//https://blog.csdn.net/qq_33404903/article/details/89425671// JvmStatic指定如果它是函數,則需要從此元素生成額外的靜態方法。// 如果此元素是屬性,則應生成額外的靜態 getter / setter 方法。@JvmStaticfun v(tag: String, msg: String): Int {return MonitorManager.commonConfig.log.v(tag, msg)}@JvmStaticfun i(tag: String, msg: String): Int {return MonitorManager.commonConfig.log.i(tag, msg)}@JvmStaticfun d(tag: String, msg: String): Int {return MonitorManager.commonConfig.log.d(tag, msg)}@JvmStaticfun w(tag: String, msg: String): Int {return MonitorManager.commonConfig.log.w(tag, msg)}@JvmStaticfun e(tag: String, msg: String): Int {return MonitorManager.commonConfig.log.e(tag, msg)}@JvmStaticfun v(tag: String, msg: String, syncToLogger: Boolean): Int {if (syncToLogger) MonitorLogger.addCustomStatEvent(tag, msg)return this.v(tag, msg)}@JvmStaticfun i(tag: String, msg: String, syncToLogger: Boolean): Int {if (syncToLogger) MonitorLogger.addCustomStatEvent(tag, msg)return this.i(tag, msg)}@JvmStaticfun d(tag: String, msg: String, syncToLogger: Boolean): Int {if (syncToLogger) MonitorLogger.addCustomStatEvent(tag, msg)return this.d(tag, msg)}@JvmStaticfun w(tag: String, msg: String, syncToLogger: Boolean): Int {if (syncToLogger) MonitorLogger.addCustomStatEvent(tag, msg)return this.w(tag, msg)}@JvmStaticfun e(tag: String, msg: String, syncToLogger: Boolean): Int {if (syncToLogger) MonitorLogger.addCustomStatEvent(tag, msg)return this.e(tag, msg)} }interface Log {fun v(tag: String, msg: String) = runIfDebug { android.util.Log.v(tag, msg) }fun i(tag: String, msg: String) = runIfDebug { android.util.Log.i(tag, msg) }fun d(tag: String, msg: String) = runIfDebug { android.util.Log.d(tag, msg) }fun w(tag: String, msg: String) = runIfDebug { android.util.Log.w(tag, msg) }fun e(tag: String, msg: String) = runIfDebug { android.util.Log.e(tag, msg) } }internal inline fun runIfDebug(block: () -> Int): Int {if (MonitorBuildConfig.DEBUG) {return block()}return -1 }16.MonitorLogger收集log,埋點
//收集log,埋點 object MonitorLogger : Logger {override fun addCustomStatEvent(key: String, value: String?, realtimeReport: Boolean) {MonitorManager.commonConfig.logger.addCustomStatEvent(key, value, realtimeReport)}override fun addExceptionEvent(message: String, crashType: Int) {MonitorManager.commonConfig.logger.addExceptionEvent(message, crashType)} }interface Logger {fun addCustomStatEvent(key: String, value: String?, realtimeReport: Boolean = false) = Unitfun addExceptionEvent(message: String, @ExceptionType crashType: Int) = Unit@IntDef(ExceptionType.UNKNOWN_TYPE,ExceptionType.OOM,ExceptionType.OOM_STACKS,ExceptionType.NATIVE_LEAK,ExceptionType.THREAD_STACKS)@Retention(AnnotationRetention.SOURCE)annotation class ExceptionType {companion object {const val UNKNOWN_TYPE = 0const val OOM = 1const val OOM_STACKS = 2const val NATIVE_LEAK = 3const val THREAD_STACKS = 4}} }17.MonitorManager保存Monitor即配置的map
object MonitorManager {internal val MONITOR_MAP = ConcurrentHashMap<Class<*>, Monitor<*>>()internal lateinit var commonConfig: CommonConfig@JvmStaticfun initCommonConfig(commonConfig: CommonConfig) = apply {this.commonConfig = commonConfig}//todo@JvmStaticfun <M : MonitorConfig<*>> addMonitorConfig(config: M) = apply {var supperType: Type? = config.javaClass.genericSuperclasswhile (supperType is Class<*>) {supperType = supperType.genericSuperclass//`getGenericSuperclass` 會包含該超類的泛型。}//ParameterizedType參數化類型if (supperType !is ParameterizedType) {throw java.lang.RuntimeException("config must be parameterized")}//取出指定的泛型。val monitorType = supperType.actualTypeArguments[0] as Class<Monitor<M>>if (MONITOR_MAP.containsKey(monitorType)) {return@apply}val monitor = try {monitorType.getDeclaredField("INSTANCE").get(null) as Monitor<M>} catch (e: Throwable) {monitorType.newInstance() as Monitor<M>}MONITOR_MAP[monitorType] = monitormonitor.init(commonConfig, config)monitor.logMonitorEvent()}@JvmStaticfun getApplication() = commonConfig.application@Deprecated("Use Monitor Directly")@JvmStaticfun <M : Monitor<*>> getMonitor(clazz: Class<M>): M {return MONITOR_MAP[clazz] as M}@Deprecated("Use Monitor#isInitialized Directly")@JvmStaticfun <M : Monitor<*>> isInitialized(clazz: Class<M>): Boolean {return MONITOR_MAP[clazz] != null}@JvmStaticfun onApplicationCreate() {registerApplicationExtension()registerMonitorEventObserver()}//onStateChanged ON_START的時候打印MONITOR_MAP的信息private fun registerMonitorEventObserver() {ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleEventObserver {private var mHasLogMonitorEvent = falseoverride fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {if (event == Lifecycle.Event.ON_START) {logAllMonitorEvent()}}private fun logAllMonitorEvent() {if (mHasLogMonitorEvent) returnmHasLogMonitorEvent = truemutableMapOf<Any?, Any?>().apply { MONITOR_MAP.forEach { putAll(it.value.getLogParams()) } }//also函數的結構實際上和let很像唯一的區別就是返回值的不一樣,let是以閉包的形式返回,// 返回函數體內最后一行的值,如果最后一行為空就返回一個Unit類型的默認值。// 而also函數返回的則是傳入對象的本身.also {MonitorLogger.addCustomStatEvent("switch-stat", JSONObject(it).toString())}}})}private fun <C> Monitor<C>.logMonitorEvent() {if (!getApplication().isForeground) returnmutableMapOf<Any?, Any?>().apply { putAll(this@logMonitorEvent.getLogParams()) }// todo 什么語法.also {MonitorLogger.addCustomStatEvent("switch-stat", JSONObject(it).toString())}} }總結
以上是生活随笔為你收集整理的koom 源码分析之 koom-monitor-base的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1096 大美数 (15 分)(测试点有
- 下一篇: 几种方法教你轻松解决电脑弹窗广告