Androidがプロセスを強制終了するシミュレーション方法


174

Androidは、プロセスがバックグラウンドにあり、OSがプロセスにリソース(RAM、CPUなど)が必要であると判断した場合、プロセスを強制終了します。テスト中にこの動作をシミュレートして、アプリケーションが正しく動作していることを確認できるようにする必要があります。これが自動化された方法で実行できるようにして、これが発生したときにアプリケーションが正しく動作するかどうかをテストできるようにします。つまり、すべてのアクティビティでこれをテストする必要があります。

プロセスを強制終了する方法を知っています。それは問題ではありません。問題は、私は私のプロセスを強制終了する場合(、DDMSを使っていることでadb shell killProcess.killProcess()Androidはそれを、それは、Android OSはそれを自分自身を殺したかどうのと同じ方法を再起動しない、など)。

Android OSが(リソース要件により)プロセスを強制終了した場合、ユーザーがアプリケーションに戻ると、Androidはプロセスを再作成し、アクティビティスタックの最上位のアクティビティを再作成します(呼び出しonCreate())。

一方、私はプロセスを殺す、Androidのアクティビティスタックの一番上に活動がひどく振る舞ったことを想定し、それがプロセスを自動的に再作成し、そのように、アクティビティスタックからトップ・アクティビティを削除し、下にいた活動を再現します最上位のアクティビティ(onCreate() `を呼び出す)。これは私が望む行動ではありません。Androidがプロセスを強制終了したときと同じ動作が必要です。

絵で説明すると、私のアクティビティスタックは次のようになります。

    ActivityA -> ActivityB -> ActivityC -> ActivityD

Androidがプロセスを強制終了し、ユーザーがアプリケーションに戻った場合、Androidはプロセスを再作成し、ActivityDを作成します。

プロセスを強制終了すると、Androidによってプロセスが再作成され、ActivityCが作成されます。


4
バックグラウンドでプロセスを強制終了するために必要な量のプロセスを作成できませんか?
Alex W


2
@Pang要点を見逃していると思います。Androidがプロセスを強制終了したことを検出する方法を知っています。これらの条件を処理するコードがあります。私がやりたいのは、このコードを適切に(そして自動化された方法で)テストすることです。そのためには、リソースのプレッシャーの下で通常行うのとまったく同じ方法で、Androidにプロセスを強制終了させる何らかの方法が必要です。リンクされた質問は興味深いですが、ここでは何の価値もありません。
David Wasser 2013


@IgorGanapolskyリンクに感謝しますが、実際にはこれらのリンクのどれも問題の解決策がありません。
デビッドワッサー2017

回答:


127

これをテストするための最良の方法はこれを行うことでした:

  • アプリケーションでActivityDを開きます
  • ホームボタンを押します
  • Terminate ApplicationAndroid StudioのLogcatウィンドウを押します(これにより、アプリプロセスが強制終了されます。必ず、デバイスを選択して、上部のLogcatドロップダウンでプロセスを実行してください)
  • Homeを長押しするか開いたアプリを使ってアプリケーションに戻ります(デバイスによって異なります)
  • アプリケーションは、再作成されたActivityDで開始します(ActivityA、ActivityB、ActivityCは無効であり、それらに戻ったときに再作成されます)

一部のデバイスでは、アプリケーション->ランチャーアイコンを使用してアプリケーション(ActivityD)に戻ることもできますが、他のデバイスでは、代わりにActivityAを開始します。

これは、Androidドキュメントがそのことについて言っていることです。

通常、ユーザーがホーム画面からタスクを再選択すると、特定の状況で、システムはタスクをクリアします(ルートアクティビティの上にあるスタックからすべてのアクティビティを削除します)。通常、これは、ユーザーが30分などの特定の時間タスクにアクセスしなかった場合に行われます。


2
回答ありがとうございます。自動テストのために自動化する方法が必要なため、私には役に立ちません。
David Wasser 2013

1
これは本当に役に立ちました。
ジョンロバーツ

6
これは自動化されていませんが、私の目的には完全に機能しました。手順2をスキップしないことが非常に重要です。これを機能させるには、DDMSでプロセスを停止する前に、アプリをバックグラウンドに送信する必要があります。ドキュメントの引用がどこから来たのか不思議に思う人のためにここにあります<activity>マニフェストのタグに関するものなので、実際にそれらがトピックに関連しているとは思えません。
トニー・チャン、

1
まさに私が必要としたもの。ありがとうございました。知らない人のために、DDMSはEclipseにあります。ウィンドウ->パースペクティブを開くと、そこにあります。
リチャード

4
または、「開発オプション」に移動し、バックグラウンド制限を「バックグラウンドプロセスなし」に設定すると、ホームを押すたびにプロセスが終了します。
Joao Gavazzi

56

これは私にとってはうまくいくようです:

adb shell am kill <package_name>

これはadb shell kill、OPで言及されているものとは異なります。

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の例では、プロセスが再作成され、ActivityDが作成されます(ActivityCではなく、他のほとんどの殺害方法がトリガーされているようです)。

申し訳ありませんが、OPには数年遅れていますが、他の人がこれを役にたてると思います。


ありがとう!これは私が探していたものです!このコマンドの動作がとは異なることを指定したいと思います adb shell am force-stop。最後の1つでは、アプリに関連するpendingIntent(通知など)も削除されますが、最初の1つは削除されません。
bonnyz 2015年

OSのソースコードを調べてメモリを解放するプロセスを強制終了したときに実行されるコードを確認する人を指します。私の賭けはと同じコードam killです。
androidguy 2017

Android 7.1 Samsung J5では動作しません。ps私のアプリを表示
Valgaal

17

別の方法、おそらくDDMSを必要としないためスクリプト可能である方法:

ワンタイムセットアップ:[開発者向けオプション]に移動し、[バックグラウンドプロセスの制限設定]を選択して、値を[標準の制限]から[バックグラウンドプロセスなし]に変更します。

プロセスを再起動する必要がある場合は、ホームボタンを押します。プロセスは強制終了されます(スタジオのlogcat / Androidモニターで確認できます-プロセスには[DEAD]のマークが付けられます)。次に、タスクスイッチャーを使用してアプリに切り替えます。


2
面白い。フォアグラウンドサービスには影響しないと思いますよね?
IgorGanapolsky 2017

2.3.3以降のAndroidを実行している実際のデバイスでこれを行う必要があるため、これは役に立ちません。
デビッドワッサー2018

13

この質問は古いですが、adb、Android Studioなどを必要としないこの質問に対する回答があります。唯一の要件はAPI 23以降です。

OSによるアプリの再起動をシミュレートするには、アプリの実行中にアプリの設定に移動し、権限を無効にしてから(有効にできます)、最近のアプリからアプリを返します。権限が無効になると、OSはアプリを強制終了しますが、保存されたインスタンスの状態は保持します。ユーザーがアプリを返すと、アプリと最後のアクティビティ(保存された状態)が再作成されます。

「バックグラウンドプロセスなし」メソッドは同じ動作を引き起こす場合がありますが、常にそうとは限りません。たとえば、アプリがバックグラウンドサービスを実行している場合、「バックグラウンドプロセスなし」は何もしません。しかし、アプリはそのサービスを含むシステムによって殺される可能性があります。アプリにサービスがある場合でも、許可方法は機能します。

例:

アプリには2つのアクティビティがあります。ActivityAはランチャーから開始されるメインアクティビティです。ActivityBはActivityAから開始されます。onCreate、onStart、onStop、onDestroyメソッドのみを表示します。Androidは、onStopを呼び出す前に常にonSaveInstanceStateを呼び出します。これは、停止状態のアクティビティはシステムによって強制終了される可能性があるためです。[ 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.

〜「アプリはそのサービスを含むシステムによって殺される可能性があります」。フォアグラウンドサービスではありません...
IgorGanapolsky 2017

@DavidWasser仕様を読んでください!developer.android.com/guide/components/services.html#Foreground フォアグラウンドサービスは、ユーザーが積極的に認識しているサービスであり、メモリ不足時にシステムが強制終了する候補ではありません。
IgorGanapolsky 2017

3
@IgorGanapolskyドキュメンテーションは、特に完全で正しい場合(残念ながら正しくありません)には優れていますが、通常は実際の個人的な観察に頼っています。私は前景Serviceが何度も殺されるのを見てきました。システムのメモリが不足していない場合でも。ほとんどのデバイスメーカーは、バッテリーの電力を節約するために、独自の「最適化」と「改善」をAndroid OSに書き込んでいます。多くのデバイスには、標準のAndroidよりもはるかに攻撃的な「キラー」があります。
デビッドワッサー2017

@DavidWasser Fair観察。それで、これらすべての年の後に、あなたは解決策を思いつきましたか?
IgorGanapolsky 2017

@IgorGanapolskyいいえ。この問題の解決策は見つかりませんでした。それが問題がまだ開かれている理由です。
デビッドワッサー2017

7

私はパーティーに非常に遅れており、同じ正しい答えを出す前に何人かいますが、ホームボタンを押して次のコマンドを実行するだけで、後から来る人のために単純化します。

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

アプリは状態を失うことはなく、私自身の経験から、これはOSがバックグラウンドでアプリを強制終了したのと同じように機能します。これは、ビルドされたアプリケーションをデバッグする場合にのみ機能します


私が得る'grep' is not recognized as an internal or external command, operable program or batch file.
デール

しかし、シェルrun-as <package name> kill 7379で実行していましたが、ホームボタンを押したときのアクティビティではなく、前のアクティビティに移動しました。
デール

6

これは、Android Studioで行う方法です。

  1. デバイスをデバッグモードでコンピューターに接続します。
  2. デバイスでアプリを開き、「死から復活」をテストするアクティビティに移動します。
  3. デバイスのホームボタンを押します。
  4. Android StudioでAndroid Monitor-> Monitorsに移動し、Terminate Applicationアイコンを押します。
  5. これで、最近のアプリからアプリに戻るか、ランチャーアイコンをクリックして、テストでの動作は同じになりました。

2
これは助けにはなりません。これをプログラム的に、テストスイート内で行う必要があります。とにかくありがとう。
デビッドワッサー2017

また、この答えはマークからの答えとほとんど同じです。
デビッドワッサー2017

UIAutomatorまたはEspressoを使用してこれを行う方法はありますか?
IgorGanapolsky 2017

見つかりませんAndroid Monitor - Monitors。彼らが取り除いたものでなければなりません。私はv 3.2.1にいます
デール

1
@Dale AndroidデバイスモニターはAndroid Studio 3.1で廃止され、Android Studio 3.2から削除されました。
Valgaal

5

HOMEボタンでアプリケーションをバックグラウンドに置きます

Android Studioの「Logcat」モードでプロセスを選択し、左下隅の[アプリケーションの終了]をクリックします

終了ボタン

Androidデバイスのランチャーからアプリを起動します


編集:インターネットによると、以下も機能します:

 adb shell am kill [my-package-name]

将来の編集:注意すべき点として、Android Studio 4.0で変更がありましたRun。ASから使用するTerminateと、Force Stop

ただし、後でランチャーから起動し、それをこの方法でシミュレートしようとすると、必要な結果が得られます(低メモリ動作)。


これは重複した回答です
Onik

@Onik他のすべてのものには、ddmsなどの不要な綿毛がたくさんあります。技術的にはそうですが、stackoverflow.com / a / 41975750/2413303でも同じことが言えます。多分私は写真を追加する必要があります。
EpicPandaForce 2018

これは役に立ちません。テストハーネスを持っていますが、テストハーネスからこれらのアクションを実行できません。また、Androidがプロセスを強制終了した場合の動作と同じではありません。
デビッドワッサー2018

the behaviour is not the same as what happens when Android kills the processはい、そうです
EpicPandaForce 2018

このプロセスでは、ホームボタンが押されたときのアクティビティではなく、前のアクティビティが表示されます。
デール

2

次のステップを実行して、求められている動作を再現できます。

  1. アプリを開き、一番上のアクティビティに移動します
  2. 通知パネルを使用して、別のフルスクリーンアプリケーションに移動します(たとえば、システム設定-右上隅)
  3. アプリケーションプロセスを強制終了する
  4. 戻るボタンを押す

1
回答ありがとうございます。自動テストのために自動化する方法が必要なため、私には役に立ちません。
David Wasser

したがって、これが実際にAndroidがメモリをクリアしてアプリを強制終了することをシミュレートする唯一の方法です(私のAPIレベルは19なので、send-trim-memoryコマンドを使用できません)。adb shell am force-stop com.my.app.packageまたはkillなどの他のコマンドは、上記の手順に従うのと同じ正確なプロセスを再現しません!
Mark Garcia、

2

[設定]の[開発者向けオプション]で、[アクティビティを保持しない]を選択します。これにより、アクティビティから移動するとすぐにアクティビティが破棄されます。

注:以下の役立つコメントに従って、静的な値がクリアされることを気にしない場合にのみこれを使用してください。


これは、1年前にすでに投稿され、拒否されたソリューションと実質的に同じです。唯一の違いは、エミュレータでの設定に使用されるアプリケーションと、それをサポートする最近の電話との違いです。
Chris Stratton

1
クリス・ストラットンが言うように、申し訳ありませんが、これは他の答えとほとんど同じ提案です。これはAndroidの仕上げ作業に関するものではありません。これは、Androidがプロセス全体を強制終了することに関するものです(特にAndroid 4.xを実行しているHTCデバイスでは、定期的かつ効果的に行われます)。
David Wasser 2013年

6
これはほとんど問題ありませんが、プロセスを強制終了することはなく、アクティビティを破壊するだけです。どういう意味ですか?アクティビティはsavedInstanceStateで開かれますが、すべての静的変数はまだ処理中です。プロセスの終了後、すべての静的変数もクリアされます。
マーク

1

ホームボタンを押して、最初にアプリをバックグラウンドにします。次に、DDMSまたはADBからプロセスを停止または強制終了します。


回答ありがとうございます。自動テストのために自動化する方法が必要なため、私には役に立ちません。
デビッドワッサー2014

Androidは、アクティビティが現在フォアグラウンドにある場合、プロセスを強制終了しません。発生しない条件をテストしようとしています。アクティビティがバックグラウンドにある場合、その状態はすでに保存されており、手動で強制終了した場合とAndroidが低メモリで強制終了した場合、つまりプロセスが強制終了されただけの場合と違いはありません。低メモリキルについて特別なことは何もありません。メモリが再び使用可能になると、スティッキーサービスが再起動され(4.4を除く)、アイコンまたは最近のタスクをタップすると、スタックとアクティビティの状態が復元されます。
Monstieur 2014

3
あなたの例では、アクティビティDが画面に表示されているときにプロセスを強制終了したため(これはメモリ不足でも発生しません)、アクティビティCの状態がバックグラウンドにあるため保存されたため、アクティビティCに戻ります。プロセスは、フォアグラウンドにない場合にのみ強制終了されます。つまり、アクティビティDの状態は、バックグラウンドに移動したときに保存され、プロセスが強制終了された場合でも復元されます。各アクティビティでテストを実行するには、アプリを強制終了する前に、まずアプリをバックグラウンドに送信する必要があります。
Monstieur 14

〜とはどういう意味ですか?アプリを最初にバックグラウンドに置きますか?
IgorGanapolsky 2017

1

を使用して端末からデバイス/エミュレータに接続し、を使用しadb shellてプロセスのPIDを取得してps | grep <your_package_nameを実行することもできkill -9 <pid>ます。次に、最近のアプリピッカーから最小化されたアプリを開くと、最後のアクティビティが再開されます


これは、メモリ不足の状況でAndroidがプロセスを強制終了するのと同じですか?OPは特にそれを望んでいたと思います
IgorGanapolsky 2017

1
@IgorGanapolskyは理論的にはそうですが、ルート化されていない場合、実際のデバイスでは実行できませんでした。
フランマルゾア2017年

0

問題の根源は、 Activityがプロセスを殺したときにあなたが前景にいるということのようです。

DDMSで停止を押すと、これを観察できます。 Activityはで表示さに(説明どおりに)停止を押して、家の後で停止を押して後でアプリに戻るのと比較することで確認できます。

必ずmoveTaskToBack(true)テストで何らかの形で確認してください。


0

これがあなたが探している答えであるかどうかはわかりませんが、それは論理的思考のようなものです。

完全に自動化されたテストを実際に行うことはできないと思います。それをシミュレートする唯一の方法は、それを再現することです。AKAには非常に多くのアクティビティがあり、Androidによってアプリケーションが強制終了されます。

したがって、私のアイデアまたは提案は、Androidがメモリを使い果たし、プロセスをバックグラウンドで強制終了するまで、新しいアクティビティをポップアップし続ける別の小さなアプリを作成することです。

行の中の何か:

アクティビティiを開始->アプリがリストにある場合は実行中のプロセスをチェックし、iをインクリメントし、現在のアクティビティを閉じずにループを再開します。それ以外の場合-> iを減らして現在のアクティビティを閉じ、前に戻って再確認します...


0

アプリケーションプロセスが終了すると、Androidはアクティビティレコードを調べ(エントリは履歴スタックのアクティビティを表します)、決定しますに保持するものと履歴から削除するものをします。

ここでの重要なポイントの1つは、Android Frameworkエンジニアが説明するActivityRecordと呼ばれるフィールドですhaveStateとして「私たちが最後の活動状態を得ています?」。

デフォルトでは、Android はアクティビティに状態があると見なします。アプリケーションがアクティビティが再開したことをアクティビティタスクマネージャサービスに報告すると、アクティビティステートレスになります。これは、アクティビティが停止状態になったことをアプリケーションフレームワークに通知するまで有効です。簡単に言うと、値は、アプリケーションのターゲットバージョンに応じて、アクティビティが呼び出されるか、呼び出されるかの間です。haveStatefalseonResume()onStop()onSaveInstanceState()

プロセスを強制終了すると、Androidによってプロセスが再作成され、ActivityCが作成されます。

この場合、ActivityDはandroid:stateNotNeeded="true"アプリケーションマニフェストに属性がなく、現在フォアグラウンドで実行されているため、システムが最後の状態になっていないため、Androidはそれを履歴から削除します。

Androidがプロセスを強制終了するシミュレーション方法

何度か言及したように、アプリケーションをバックグラウンドに移動するだけで、アクティビティバックスタックの最上位のアクティビティがその状態を保存し、その後、Android Debug Bridge、Android Studio、または開発者オプションのバックグラウンドプロセス制限プロパティ。その後、最近のアクティビティが正常に再作成されます。

それにもかかわらず、アプリケーションプロセスの死のシナリオをテストする別の簡単な方法もあります。上記のすべてと、現在実行中のActivityDから新しいActivityEを開始する場合onStop()、ActivityD onResume()メソッドの後にのみActivityD コールバックが呼び出されるという事実を知っていると、次のトリックを実行できます。

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と呼ばれる、アプリケーションプロセスの終了のテストを簡素化する軽量ツールがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.