codememo

Android가 프로세스를 죽이는 시뮬레이션 방법

tipmemo 2023. 8. 6. 10:07
반응형

Android가 프로세스를 죽이는 시뮬레이션 방법

Android는 프로세스가 백그라운드에 있고 OS가 리소스(RAM, CPU 등)가 필요하다고 판단하면 프로세스를 종료합니다.테스트 중에 이 동작을 시뮬레이션할 수 있어야 응용 프로그램이 올바르게 작동하는지 확인할 수 있습니다.자동화된 방식으로 이 작업을 수행하여 응용프로그램이 올바르게 작동하는지 테스트할 수 있기를 원합니다. 즉, 모든 작업 등에서 이 작업을 테스트해야 합니다.

내 과정을 죽이는 방법을 알고 있습니다.그게 문제가 아닙니다. 과정을 때 (하면, DDMS를 사용하면)adb shell kill,Process.killProcess()등) Android는 Android OS가 자체적으로 삭제한 경우와 동일한 방식으로 재시작하지 않습니다.

리소스 요구 사항으로 인해 Android OS가 프로세스를 종료한 경우 사용자가 애플리케이션으로 돌아갈 때 Android는 프로세스를 다시 만든 다음 활동 스택에서 최상위 활동을 다시 만듭니다(호출).onCreate()).

반면에 제가 프로세스종료하면 Android는 작업 스택의 맨 에 있는 작업이 잘못 수행된 으로 간주하여 프로세스를 자동으로 다시 생성한 다음 작업 스택에서 맨 위의 작업을 제거하고 맨 아래에 있던 작업을 다시 생성합니다(Create()' 호출).이것은 내가 원하는 행동이 아닙니다.안드로이드가 프로세스를 종료할 때와 동일한 동작을 원합니다.

그림으로 설명하자면, 내 활동 스택이 다음과 같은 경우:

    ActivityA -> ActivityB -> ActivityC -> ActivityD

Android가 프로세스를 종료하고 사용자가 애플리케이션으로 돌아오면, Android는 프로세스를 다시 생성하고 ActivityD를 만듭니다.

제가 프로세스를 종료하면 안드로이드는 프로세스를 다시 생성하고 ActivityC를 생성합니다.

이것을 테스트하는 가장 좋은 방법은 다음과 같습니다.

  • 응용프로그램에서 활동 D 열기
  • 홈 버튼을 누릅니다.
  • 를 누릅니다.Terminate ApplicationAndroid Studio의 Logcat 창(앱 프로세스가 중지됩니다. 장치를 선택하고 상단의 Logcat 드롭다운에서 프로세스를 수행하십시오.)
  • 홈에서 길게 누르거나 열려 있는 앱(장치에 따라 다름)을 사용하여 응용프로그램으로 합니다.
  • 다시 작성된 활동 D에서 응용 프로그램이 시작됩니다(활동 A, 활동 B, 활동 C는 비활성 상태이며 해당 활동으로 돌아가면 다시 작성됩니다).

일부 장치에서는 Applications -> Launcher 아이콘을 사용하여 응용 프로그램(ActivityD)으로 돌아갈 수도 있지만 다른 장치에서는 대신 ActivityA를 시작합니다.

Android 문서는 다음과 같이 말합니다.

일반적으로 사용자가 홈 스크린에서 작업을 다시 선택하면 특정 상황에서 시스템은 작업을 삭제합니다(루트 활동 위의 스택에서 모든 활동 제거).일반적으로 이 작업은 사용자가 특정 시간(예: 30분) 동안 작업을 방문하지 않은 경우에 수행됩니다.

이것은 저에게 효과가 있는 것 같습니다.

adb shell am kill <package_name>

은 이다음다다니와 다릅니다.adb shell killOP가 언급한.

로 을참시오십고하말에 도움말입니다.am kill명령은 다음과 같습니다.

am kill: Kill all processes associated with <PACKAGE>.  Only kills.
  processes that are safe to kill -- that is, will not impact the user
  experience.

따라서, 그것이 전경에 있다면 그것은 과정을 죽이지 않습니다.앱에서 벗어나 탐색하면 실행한다는 점에서 OP가 원하는 대로 작동하는 것 같습니다.adb shell am kill <package_name>그것은 앱을 죽일 것입니다 (저는 이것을 사용하여 확인했습니다.ps장치에 있음).그런 다음 앱으로 돌아가면 이전에 했던 활동으로 돌아갑니다. 즉, OP의 예에서 프로세스가 다시 생성되고 대부분의 다른 살해 방법과 같은 활동 C가 아니라 활동 D가 만들어집니다.

작전에 몇 년이나 늦어서 미안하지만, 다른 사람들이 이것을 유용하게 여길 수 있기를 바랍니다.

DDMS가 필요하지 않기 때문에 스크립트로 작성할 수 있는 다른 방법:

한 번 설정: 개발자 옵션으로 이동하여 백그라운드 프로세스 제한 설정을 선택하고 값을 '표준 제한'에서 '백그라운드 프로세스 없음'으로 변경합니다.

프로세스를 다시 시작해야 할 경우 홈 버튼을 누릅니다.프로세스가 중지됩니다(스튜디오의 logcat/Android Monitor에서 확인할 수 있습니다. 프로세스는 [DEAD]로 표시됩니다).그런 다음 작업 전환기를 사용하여 앱으로 다시 전환합니다.

HOME 버튼을 사용하여 응용프로그램을 백그라운드에 배치합니다.

Android Studio에서 "Logcat" 모드로 프로세스를 선택한 후 왼쪽 하단 모서리에서 Terminate Application(애플리케이션 종료)을 클릭합니다.

terminate button

이제 Android 기기의 런처에서 앱 실행


편집: 인터넷에 따르면 다음과 같은 기능도 합니다.

 adb shell am kill [my-package-name]

향후 편집:주의할 점은 안드로이드 스튜디오 4.0에 변경 사항이 있다는 것입니다.Run으로 그면에 AS에서Terminate을 발행할 것입니다.Force Stop.

그러나 나중에 시작 프로그램에서 시작한 다음 이 방법으로 시뮬레이션을 시도하면 원하는 결과가 나타납니다(메모리 부족 동작).

이 질문은 오래된 질문이지만, 이 질문에 대한 답은 adb, Android Studio 등이 필요하지 않습니다.유일한 요구 사항은 API 23 이상입니다.

OS에 의한 앱 재시작을 시뮬레이션하려면 앱이 실행되는 동안 앱 설정을 이동하고, 권한을 비활성화(활성화)한 후 최근 앱에서 앱을 반환합니다.사용 권한이 비활성화되면 OS는 앱을 종료하지만 저장된 인스턴스 상태는 유지합니다.사용자가 앱을 반환하면 앱과 마지막 활동(저장된 상태)이 다시 생성됩니다.

'백그라운드 프로세스 없음' 메서드는 때때로 동일한 동작을 유발하지만 항상은 아닙니다.예를 들어, 앱이 백그라운드 서비스를 실행 중인 경우 "백그라운드 프로세스 없음"은 아무 작업도 수행하지 않습니다.그러나 앱은 서비스를 포함한 시스템에 의해 삭제될 수 있습니다.앱에 서비스가 있어도 허가 방법이 작동합니다.

예:

우리 앱은 두 가지 활동이 있습니다.활동 A는 런처에서 시작되는 주요 활동입니다.활동 B는 활동 A에서 시작됩니다.Create, Start, Stop, Destroy 메서드에만 표시합니다.중지 상태에 있는 활동이 시스템에 의해 중지될 수 있으므로 Android는 중지를 호출하기 전에 항상 SaveInstanceState를 호출합니다.[https://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle ]

권한 방법:

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop (the order is like this, it is stopped after new one is started)
<go settings>
ActivityB onStop
<disable a permission>
//Application is killed, but onDestroy methods are not called.
//Android does not call onDestroy methods if app will be killed.
<return app by recent apps>
Application onCreate (this is the important part. All static variables are reset.)
ActivityB onCreate WITH savedInstance (user does not notice activity is recreated)
//Note that ActivityA is not created yet, do not try to access it.
ActivityB onStart
<return ActivityA by back>
ActivityA onCreate WITH savedInstance (user does not notice activity is recreated)
ActivityA onStart
ActivityB onStop
ActivityB onDestroy
<press back again, return launcher>
ActivityA onStop
ActivityA onDestroy
<open app again>
//does not call Application onCreate, app was not killed
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart

저는 다른 답변에 언급된 다른 방법들을 비교하고 싶습니다.

활동 보관 안 함:이렇게 하면 응용 프로그램이 중지되지 않습니다.

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop
ActivityA onDestroy (do not keep)
<return launcher by home button>
ActivityB onStop
ActivityB onDestroy (do not keep) 
<retun app from recent apps>
// NO Application onCreate
ActivityB onCreate WITH savedInstance (user does not notice activity recreated)
ActivityB onStart
<return ActivityA by back>
ActivityA onCreate WITH savedInstance (user does not notice activity recreated)
ActivityA onStart
ActivityB onStop
ActivityB onDestroy
<press back again, return launcher>
ActivityA onStop
ActivityA onDestroy
<open app again>
//does not call Application onCreate, app was not killed
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart

강제 중지 방법:저장된 인스턴스 상태를 저장하지 않습니다.

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop
<go settings>
ActivityB onStop
<force stop, return app from recent apps>
Application onCreate
ActivityA onCreate WITHOUT savedInstance 
//This is important part, app is destroyed by user.
//Root activity of the task is started, not the top activity.
//Also there is no savedInstance.

저는 파티에 매우 늦었고 제 앞에 있는 몇몇 사람들도 같은 답을 했지만, 제 뒤에 오는 사람들은 간단하게 홈 버튼을 누르고 다음 명령을 실행하세요.

adb shell ps | grep <package name> | awk '{print $2}' | xargs adb shell run-as <package name again> kill

앱은 상태를 잃지 않을 것이며 제 경험에 따르면 이것은 OS가 백그라운드에서 앱을 제거한 것과 동일한 방식으로 작동합니다.디버그 빌드 응용 프로그램에서만 작동합니다.

Android Studio에서는 이렇게 합니다.

  1. 디버그 모드의 장치를 컴퓨터에 연결합니다.
  2. 단말기에서 앱을 열고 "Return to it from the dead"를 테스트할 활동으로 이동합니다.
  3. 단말기의 홈 버튼을 누릅니다.
  4. Android Studio에서 Android Monitor -> Monitors(안드로이드 모니터)로 이동한 후 Terminate Application(애플리케이션 종료) 아이콘을 누릅니다.
  5. 이제 최신 앱을 통해 앱으로 돌아가거나 런처 아이콘을 클릭하면 제 테스트에서도 동작이 동일했습니다.

다음 단계를 수행하여 원하는 동작을 재현할 수 있습니다.

  1. 앱을 열고 상위 활동으로 이동합니다.
  2. 알림 패널을 사용하여 다른 전체 화면 응용 프로그램(예: 시스템 설정 - 오른쪽 상단 모서리)으로 이동합니다.
  3. 애플리케이션 프로세스 중단
  4. 뒤로 누르기 버튼

응용 프로그램 프로세스가 종료되면 Android는 작업 기록(항목은 기록 스택의 작업을 나타냄)을 검토하고 기록에 유지할 작업 기록과 삭제할 작업 기록을 결정합니다.

한 점 중 는 서중점중하는나여요입니다.ActivityRecord라는 haveStateAndroid Framework 엔지니어가 "마지막 활동 상태를 파악했습니까?"라고 설명하는 항목입니다.

기본적으로 Android는 활동에 상태가 있다고 간주합니다.활동이 재개되었음을 활동 작업 관리자 서비스에 보고하면 활동이 상태 비저장 상태가 되며, 이는 활동이 중지됨 상태로 전환되었음을 응용 프로그램이 프레임워크에 알릴 때까지 유효합니다.간단히 말하면,haveState은 은입니다.false onResume()라고 부릅니다.onStop()또는onSaveInstanceState()응용 프로그램 대상 버전에 따라 호출됩니다.

제가 프로세스를 종료하면 안드로이드는 프로세스를 다시 생성하고 ActivityC를 생성합니다.

에는 "D"라는 단어가 .android:stateNotNeeded="true"속성은 응용 프로그램 매니페스트에 있으며 현재 포그라운드에서 실행 중이므로 Android는 시스템이 마지막 상태를 얻지 못했기 때문에 기록에서 제거합니다.

Android가 프로세스를 죽이는 시뮬레이션 방법

여러 번 언급했듯이 응용프로그램을 백그라운드로 이동하기만 하면 작업 백스택의 최상위 활동이 해당 상태를 저장한 후 Android Debug Bridge, Android Studio 또는 Developer Options의 Background Processes Limit 속성을 사용하여 응용프로그램 프로세스를 종료할 수 있습니다.그런 다음 최근 활동이 성공적으로 재생성됩니다.

그럼에도 불구하고, 애플리케이션 프로세스 사망 시나리오를 테스트하는 또 다른 간단한 방법이 있습니다. 것과 중인 ActivityD에서 가 D에서 E로 을 알고 .onStop()콜백은 활동 E 이후에만 호출됩니다.onResume()방법, 당신은 다음과 같은 트릭을 할 수 있습니다.

class TerminatorActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val isPrePie = applicationInfo.targetSdkVersion < Build.VERSION_CODES.P
        val callbacks = TerminatorLifecycleCallbacks(isPrePie)
        (applicationContext as Application).registerActivityLifecycleCallbacks(callbacks)
    }

    private class TerminatorLifecycleCallbacks(
        // Before P onSaveInstanceState() was called before onStop(), starting with P it's
        // called after
        // Used to schedule the death as app reports server that activity has stopped
        // after the latest of these was invoked
        private val isPrePie: Boolean
    ) : ActivityLifecycleCallbacksDefault {

        private val handler = Handler(Looper.getMainLooper())

        override fun onActivityPostStopped(activity: Activity) {
            if (isPrePie) {
                terminate()
            }
        }

        override fun onActivityPostSaveInstanceState(activity: Activity, outState: Bundle) {
            if (!isPrePie) {
                terminate()
            }
        }

        fun terminate() {
            handler.postDelayed(
                {
                    Process.killProcess(Process.myPid()) // This is the end... 
                },
                LAST_MILLIS
            )
        }

        companion object {
            // Let's wait for a while, so app can report and server can handle the update
            const val LAST_MILLIS = 100L
        }

    }

    private interface ActivityLifecycleCallbacksDefault : Application.ActivityLifecycleCallbacks {
        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
        override fun onActivityStarted(activity: Activity) {}
        override fun onActivityResumed(activity: Activity) {}
        override fun onActivityPaused(activity: Activity) {}
        override fun onActivityStopped(activity: Activity) {}
        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
        override fun onActivityDestroyed(activity: Activity) {}
    }
}

시작해요 ㅠㅠㅠㅠㅠㅠㅠTerminatorActivity응용 프로그램을 종료할 때 사용합니다.

마지막에는 Venom이라고 하는 응용 프로그램 프로세스 중단 테스트를 단순화하는 경량 도구가 있습니다.

프로그래밍 방식으로 앱 배경을 지정한 다음 다음 ADB 명령을 실행합니다.

adb shell am kill <PACKAGE_NAME>

" " " 와 다릅니다." .adb shell kill와자하트 카림의 이 훌륭한 기사에서 더 많이 설명했듯이, https://wajahatkarim.com/2020/03/defending-your-app/ .

이것은 adb shell kill 명령과는 다릅니다.이 명령은 앱 종료 버튼과 같은 앱의 전체 프로세스를 종료하고 adb 셸 암 킬은 메모리, CPU 등의 리소스를 재할당하기 위해 제거해도 안전한 프로세스만 종료합니다.

홈 버튼을 누르고 앱을 먼저 배경에 놓습니다.그런 다음 DDMS 또는 ADB에서 프로세스를 중지하거나 종료합니다.

또한 터미널에서 장치/에뮬레이터에 연결할 수 있습니다.adb shell 그 다 음 프 스 를 가 옵 니 다 져 런 의 세 로 ▁with 니 ▁pid 다 ▁process 옵 ▁then ▁your ▁get 그 ▁of 가런 져ps | grep <your_package_name 행실을 실행합니다.kill -9 <pid> 다음 앱됩니다.

참고: 아래의 유용한 설명에 따르면, 정적 값이 지워지는 것에 대해 신경 쓰지 않는 경우에만 이 기능을 사용하십시오.

설정 아래의 개발자 옵션에서 '활동 유지 안 함'을 선택합니다. 그러면 활동에서 벗어나 탐색하는 즉시 활동이 삭제됩니다.

당신의 문제의 근본은 당신의Activity프로세스를 종료할 때 전경에 있습니다.

하기 위해 "" "에서" "DDMS에서 "를 볼 수 있습니다.Activity를 볼 수 있으며(설명한 내용과 동일), 집에서 중지를 누른 후 나중에 앱으로 돌아가는 것과 비교합니다.

꼭부립니다드탁다▁sure▁make.moveTaskToBack(true)어떻게든 당신의 테스트에서.

이것이 당신이 찾고 있는 답인지 확신할 수 없습니다. 논리적 사고에 가깝습니다.

저는 당신이 완전히 자동화된 테스트를 만들 수 있다고 생각하지 않습니다. 그것을 시뮬레이션하는 유일한 방법은 그것을 다시 만드는 것입니다. AKA에는 너무 많은 활동이 있어서 안드로이드가 당신의 애플리케이션을 죽일 것입니다.

그래서 제 아이디어나 제안은 안드로이드가 메모리를 다 쓰고 프로세스를 죽이기 시작할 때까지 새로운 활동을 계속해서 나타나는 또 다른 작은 앱을 만드는 것입니다.

대사 중에 뭔가가 있습니다.

활동 시작 i -> 앱이 목록에 있으면 실행 중인 프로세스를 확인하고, 현재 활동을 닫지 않고 i를 증분하고 루프를 다시 시작합니다. 그렇지 않으면 -> i를 줄이고 현재 활동을 닫으십시오. 이전으로 돌아가서 다시 확인하십시오.

답변:

에뮬레이터에서 앱을 실행한 다음 다음 명령을 실행합니다.

adb root
adb shell ps | grep com.your.app_package | awk '{print $2}' | xargs adb shell kill

설명:

에뮬레이터가 필요한 이유는?루트 액세스 권한을 얻을 수 있기 때문입니다. 액세스 권한이 다음 합니다.kill명령:

/system/bin/sh: kill: <PID>: Operation not permitted

일반적으로 이 오류를 해결하기 위해 실제 장치에 대한 루트 액세스 권한을 얻을 수 없습니다.다음 오류가 발생합니다.adb root명령:

adbd cannot run as root in production builds

언급URL : https://stackoverflow.com/questions/11365301/how-to-simulate-android-killing-my-process

반응형