투케이2K

441. (kotlin/코틀린) [유틸 파일] getAppExitReason : getHistoricalProcessExitReasons 사용해 앱 종료 원인 확인 본문

Kotlin

441. (kotlin/코틀린) [유틸 파일] getAppExitReason : getHistoricalProcessExitReasons 사용해 앱 종료 원인 확인

투케이2K 2023. 11. 27. 19:18

[개발 환경 설정]

개발 툴 : AndroidStudio

개발 언어 : Kotlin

 

[소스 코드]

 

        // -----------------------------------------------------------------------------------------
        // TODO [SEARCH FAST] : [RETURN] getAppExitReason : 이전 앱 종료 된 원인 확인 수행
        // -----------------------------------------------------------------------------------------
        fun getAppExitReason(mContext: Context, packageName: String): String {

            /**
             * // -----------------------------------------
             * [getAppExitReason 메소드 설명]
             * // -----------------------------------------
             * 1. 이전 앱 수행 후 종료 된 원인 확인
             * // -----------------------------------------
             * 2. 호출 방식 :
             *
             * C_App.getAppExitReason(A_Intro@this, "com.example.javaproject")
             *
             * // -----------------------------------------
             * 3. 리턴 데이터 : 앱 종료 된 원인 로그 리턴
             *
             * ProcessName : com.example.javaproject
             * ProcessId : 19470
             * ExitDate : 2023-11-27 09:47:25:827
             * ExitReason : 사용자 요청으로 인해 애플리케이션 프로세스가 종료되었습니다
             * ExitDescription : stop com.example.javaproject due to from pid 20148
             * // -----------------------------------------
             * 4. TODO 추가 설명 :
             *
             * ActivityManager : 앱 활동, 서비스 및 프로세스에 대한 정보를 제공합니다
             * ActivityManager 는 디버깅 또는 정보 제공 목적으로 사용되며 앱의 런타임 동작에 영향을 주는 데 사용되어서는 안 됩니다
             *
             * // -----------------------------------------
             * 5. 참 고 :
             *
             * https://developer.android.com/reference/android/app/ActivityManager
             * https://developer.android.com/reference/android/app/ApplicationExitInfo
             * // -----------------------------------------
             */


            // [리턴 값 선언]
            var returnData = ""
            var M_LOG = ""


            // [로직 처리 실시]
            try {

                // [인풋 패키지 명칭 널 체크 수행]
                if (C_Util.stringNotNull(packageName) === true) {

                    // [ActivityManager 인스턴스 생성]
                    val manager = mContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager


                    // [앱 종료 로그 획득 실시]
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

                        // [앱 종료 로그 획득 : getHistoricalProcessExitReasons] : [10 개 지정]
                        val exitList: List<ApplicationExitInfo> = manager.getHistoricalProcessExitReasons(packageName, 0, 10)

                        // [널 체크 수행]
                        if (exitList != null && exitList.size > 0) {

                            // [종료 시간 기준으로 정렬]
                            exitList.sortedByDescending { it-> it.timestamp }

                            // [for 문을 수행하면서 로그 확인]
                            var reason = ""

                            for (i in exitList.indices) {
                                reason = "\n\n" // [초기화]

                                // [ApplicationExitInfo 생성]
                                val exitInfo = exitList[i] as ApplicationExitInfo
                                reason += "ProcessName : ${exitInfo.processName}" + "\n"
                                reason += "ProcessId : ${exitInfo.pid}" + "\n"
                                reason += "ExitDate : ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(Date(exitInfo.timestamp))}" + "\n"

                                if (exitInfo.reason == ApplicationExitInfo.REASON_ANR){
                                    reason += "ExitReason : 응답이 없어(ANR) 애플리케이션 프로세스가 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_CRASH){
                                    reason += "ExitReason : 소스코드에서 처리되지 않은 예외로 인해 애플리케이션 프로세스가 중단되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_CRASH_NATIVE){
                                    reason += "ExitReason : 네이티브 충돌로 인해 애플리케이션 프로세스가 중단되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_DEPENDENCY_DIED){
                                    reason += "ExitReason : 종속성이 사라져 애플리케이션 프로세스가 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE){
                                    reason += "ExitReason : 과도한 리소스 사용으로 인해 시스템에서 응용 프로그램 프로세스가 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_EXIT_SELF){
                                    reason += "ExitReason : System.exit() 종료 코드 사용으로 프로세스가 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_FREEZER){
                                    reason += "ExitReason : 응용 프로그램 프로세스가 정지된 동안 동기화 바인더 트랜잭션을 수신했기 때문에 App Freezer 에 의해 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_INITIALIZATION_FAILURE){
                                    reason += "ExitReason : 초기화 실패로 인해 애플리케이션 프로세스가 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_LOW_MEMORY){
                                    reason += "ExitReason : 응용 프로그램 프로세스가 시스템 메모리 부족으로 인해 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_OTHER){
                                    reason += "ExitReason : 앱에서 조치를 취할 수 없는 다양한 다른 이유로 인해 시스템에서 애플리케이션 프로세스를 종료했습니다 (ex : 시스템 업데이트)" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_PERMISSION_CHANGE){
                                    reason += "ExitReason : 런타임 권한 변경으로 인해 애플리케이션 프로세스가 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_SIGNALED){
                                    reason += "ExitReason : OS 신호의 결과로 인해 애플리케이션 프로세스가 중단되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_UNKNOWN){
                                    reason += "ExitReason : 알 수 없는 이유로 프로세스가 중단되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_USER_REQUESTED){
                                    reason += "ExitReason : 사용자 요청으로 인해 애플리케이션 프로세스가 종료되었습니다" + "\n"
                                }
                                else if (exitInfo.reason == ApplicationExitInfo.REASON_USER_STOPPED){
                                    reason += "ExitReason : 여러 사용자가 있는 장치에서 실행 중인 사용자가 중지되었기 때문에 응용 프로그램 프로세스가 종료되었습니다" + "\n"
                                }
                                else {
                                    reason += "ExitReason : ${exitInfo.reason}" + "\n"
                                }

                                reason += "ExitDescription : ${exitInfo.description}" + "\n"

                                // ---------------------------------------

                                // [단일 로그 확인 및 리턴]
                                if (i == 0) {
                                    M_LOG = "[Success] :: Get Exit Reason Check"
                                    returnData = reason
                                    break // [반복문 종료]
                                }

                                // ---------------------------------------

                                // [전체 출력 시 로그]
                                /*
                                S_Log._W_("Get Exit Log [" + i.toString() + "]", arrayOf(
                                    reason.toString()
                                ))
                                // */

                                // ---------------------------------------
                            }
                        } else {
                            M_LOG = "[Error] :: Get exitList Fail :: Reason :: Exit List Is Null"
                        }
                    } else {
                        M_LOG = "[Error] :: Get exitList Fail :: Reason :: Android Version 11 Low"
                    }
                } else {
                    M_LOG = "[Error] :: Input Data Is Null"
                }

            } catch (e: Exception) {
                M_LOG = "[Exception] :: " + e.message.toString()
                S_Log._printStackTrace_(mContext, S_FinalMsg.LOG_BUG_STATE, null, e)
            }


            // [로그 출력 실시]
            ///*
            // ===============================================================
            S_Log._D_("이전 앱 수행 후 종료 된 원인 확인", arrayOf(
                "INPUT :: $packageName",
                "M_LOG :: $M_LOG",
                "RETURN :: $returnData"
            ))
            // ===============================================================
            // */


            // [리턴 반환 실시]
            return returnData
        }

 

반응형
Comments