2010年12月20日月曜日

Android Android 2.3 - StrictMode -

・StrictMode とは、開発者がアプリケーションをモニターし、パフォーマンスを改善するために新しく追加されたシステム機能

・この機能を実装すると、StrictMode はアプリケーションのパフォーマンスを低下させる accidental disk や network activity を捕捉し、開発者にしらせてくれる

・例えば、メインスレッド上での accidental disk や network activity など

・開発者は StrictMode が補足した network や disk usages の問題を評価し、必要ならば修正できる

・これにより、メインスレッドは応答性を維持し、ANRダイアログがユーザーに表示されることを防げる


 - StrictMode
   core class であり、システムとVMを統合する主要なポイント。
   このクラスは、インスタンスに応用するスレッドとVMのポリシーを
   管理するための便利なメソッドを提供する

 - StrictMode.ThreadPolicyStrictMode.VmPolicy
   スレッドとVMのインスタンスに応用するための(自分の)
   ポリシーを保持する  
 
---------------------------------------------------------

New Gingerbread API: StrictMode - Android developers Blog より

・StrictMode は Thread のポリシーに、どの操作を違反とし、違反があったときに何をするかを定義する

・デフォルトでは、全ての操作が許可されている

・thread ポリシーに含むことができるフラグとして、例えば以下のものがある

  ・detect disk writes
  ・detect disk reads
  ・detect network usage
  ・on a violation: log
     > adb logcat で見ることが可能
  ・on a violation: crash
  ・on a violation: dropbox
     DropBoxManager に書き込まれ、後から抽出できる
     > adb shell dumpsys dropbox data_app_strictmode --print
  ・on a violation: show an annoying dialog

・StrictMode の強力な点は、スレッドあたりのポリシーは他の Serivces や Providers によって Binder IPC コールが作成されるたびに伝搬し、スタックトレースは任意の数のプロセスでつなぎあわされたものになること

・メインスレッドでネットワークリクエストをしてはいけない。Honeycomb リリースでは、メインスレッドでのネットワークリクエストは fatal error になるように作られている(らしい)

Android Market にリリースする前に StrictMode を除くのを忘れずに!

StrictMode を使うには、 onCreate() で
  1. public void onCreate() {  
  2.     if (DEVELOPER_MODE) {  
  3.         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
  4.                 .detectDiskReads()  
  5.                 .detectDiskWrites()  
  6.                 .detectNetwork()  
  7.                 .penaltyLog()  
  8.                 .build());  
  9.     }  
  10.     super.onCreate();  
  11. }  

もっと簡単に
  1. public void onCreate() {  
  2.  if (DEVELOPER_MODE) {  
  3.      StrictMode.enableDefaults();  
  4.  }  
  5.  super.onCreate();  


・Gingerbread 以前の API をターゲットにしたアプリケーションを Gingerbread 以降の端末やエミュータで実行する場合、reflection や 他の方法 を使って StrictMode を有効にできる

・問題が見つかったら、Threadjava.util.concurrent.* に加えて Handler, AsyncTask, AsyncQueryHandler, IntentService なども活用する

・Android 2.3 から SharedPreference.Editor() に apply() メソッドが追加された。commit() の戻りを使わない場合は apply() に置き換えられる。

# commit() は永続化ストレージに設定を同期して書き込むが、apply()は in-memory の SharedPreferences にすぐにコミットし、ディスクへのコミットは非同期に行われる。そのため、UIスレッドをブロックしない。

---------------------------------------------------------



 ■ StrictMode.ThreadPolicy

  特定のスレッドに適用するポリシー

  setThreadPolicy(StrictMode.ThreadPolicy) メソッドで有効にする

  現在のポリシーは getThreadPolicy() で取得する

  注意: 複数のペナルティを設定することは可能だが、検出された異なる
  アクションに異なるペナルティを選択することは現状ではできない。

  StrictMode.ThreadPolicy.Builder を使ってインスタンスを生成する

  ・ Nested Classes
    
    - StrictMode.ThreadPolicy.Builder
       StrictMode.ThreadPolicy インスタンスを生成する

  ・ Constants
    - LAX
       デフォルトのポリシー。lax policy は何も捕捉しない

 ■ StrictMode.ThreadPolicy.Builder

  StrictMode.ThreadPolicy インスタンスを生成する

  "detect" から始まるメソッドで補足したい問題の検出を有効にする

  "permit" から始まるメソッドで捕捉したい問題の検出を無効にする

  "penalty" から始まるメソッドで問題を検出したときにすべきことを指定する

  複数の detect と penalty メソッドを呼ぶことができる
  順番は問題に関係く、全てのペナルティは全ての検出された問題に適用される

  全てを検出して、すべてをログに出すには次のようにする
  1. StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()  
  2.     .detectAll()  
  3.     .penaltyLog()  
  4.     .build();  
  5. StrictMode.setThreadPolicy(policy);  


  ・ Public Methods

    - build ()
       ThreadPolicy instance を生成
       build メソッドが呼ばれるまえに、ペナルティがなにも
       セットされていない場合は、penaltyLog() が暗黙に
       セットされる

    - detectAll ()
       可能性のある候補すべてを検出する
       Gingerbread release では、 SQLiner cursor leaks だけ
       含まれるが、将来の release で拡張される

    - detectDiskReads ()
       disk reads の検出を有効にする

    - detectDiskWrites ()
       disk writes の検出を有効にする

    - detectNetwork()
       ネットワーク操作の検出を有効にする

    - penaltyDeath ()
       違反によって全てのプロセスをクラッシュする
       このペナルティは全ての有効なペナルティの最後に行われる。
       そのため、プロセスが終了する前にログや他の違反を
       取ることが可能

    - penaltyDialog ()

       違反を検出するとダイアログを表示する
       これにより、少しレートが制限される

    - penaltyDropBox ()
       検出された違反のスタックトレースとタイミングデータを
       DropBox にログとして出すことを有効にする
       ベータユーザーのフィールドデータ収集する platform
       integrator を主な対象としている

    - penaltyLog ()
       検出された違反をシステムログに出す

    - permitAll ()
       全ての検出を無効にする

    - permitDiskReads ()
       disk reads の検出を無効にする

    - permitDiskWrites ()
       disk writes の検出を無効にする

    - permitNetwork ()
       ネットワーク操作の検出を無効にする


 ■ StrictMode.VmPolicy

  virtual machine 上のプロセスの全てのスレッドに適用するポリシー
   
  setVmPolicy(StrictMode.VmPolicy) メソッドで有効にする

  StrictMode.VmPolicy.Builder を使ってインスタンスを生成する

  ・ Nested Classes
    
    - StrictMode.VmPolicy.Builder
       StrictMode.VMPolicy インスタンスを生成する

  ・ Constants
    - LAX
       デフォルトのポリシー。lax policy は何も捕捉しない

 ■ StrictMode.Vmpolicy.Builder

  StrictMode.VmPolicy インスタンスを生成する

  "detect" から始まるメソッドで補足したい問題を指定する

  "penalty" から始まるメソッドで問題を検出したときに
  すべきことを指定する

  複数の detect と penalty メソッドを呼ぶことができる
  順番は問題に関係く、全てのペナルティは全ての検出された
  問題に適用される

  全てを検出して、すべてをログに出すには次のようにする
  1. StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()  
  2.     .detectAll()  
  3.     .penaltyLog()  
  4.     .build();  
  5. StrictMode.setVmPolicy(policy);  


  ・ Public Methods

    - build ()
       VmPolicy instance を生成
       build メソッドが呼ばれるまえに、ペナルティがなにも
       セットされていない場合は、penaltyLog() が暗黙に
       セットされる

    - detectAll ()
       可能性のある候補すべてを検出する
       Gingerbread release では、 SQLiner cursor leaks だけ
       含まれるが、将来の release で拡張される

    - detectLeakedSqlLiteObjects ()
       SQLiteCursor や他の SQLite object がクローズされずに
       finalize されたときに検出する
       不要なデータベースの競合と一時的なメモリリークを防ぐ
       ために、SQLite cursor は明示的にクローズするべき

    - penaltyDeath ()
       違反によって全てのプロセスをクラッシュする
       このペナルティは全ての有効なペナルティの最後に行われる。
       そのため、プロセスが終了する前にログや他の違反を
       取ることが可能

    - penaltyDropBox ()
       検出された違反のスタックトレースとタイミングデータを
       DropBox にログとして出すことを有効にする
       ベータユーザーのフィールドデータ収集する platform
       integrator を主な対象としている

    - penaltyLog ()
       検出された違反をシステムログに出す


試しにUIスレッドでインターネットダウンロードしてみました。
  1. package yanzm.example.strictmodesample;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.http.HttpResponse;  
  6. import org.apache.http.HttpStatus;  
  7. import org.apache.http.client.ClientProtocolException;  
  8. import org.apache.http.client.methods.HttpGet;  
  9. import org.apache.http.impl.client.DefaultHttpClient;  
  10.   
  11. import android.app.Activity;  
  12. import android.graphics.Bitmap;  
  13. import android.graphics.BitmapFactory;  
  14. import android.os.Bundle;  
  15. import android.os.StrictMode;  
  16.   
  17. public class MyActivity extends Activity {  
  18.   
  19.   private boolean DEVELOPER_MODE = true;  
  20.   
  21.   @Override  
  22.   public void onCreate(Bundle savedInstanceState) {  
  23.   
  24.     if (DEVELOPER_MODE) {  
  25.       StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
  26.         .detectDiskReads()  
  27.         .detectDiskWrites()  
  28.         .detectNetwork()  
  29.         .penaltyLog()  
  30.         .build());  
  31.       StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()  
  32.         .detectLeakedSqlLiteObjects()  
  33.         .penaltyLog()  
  34.         .penaltyDeath()  
  35.         .build());  
  36.     }  
  37.     super.onCreate(savedInstanceState);  
  38.   
  39.     downloadFromInternet();  
  40.   }  
  41.   
  42.   private void downloadFromInternet() {  
  43.   
  44.     String url = "https://sites.google.com/site/yukianzm/tmp/image1.png";  
  45.   
  46.     try {  
  47.       Bitmap bmp = null;  
  48.   
  49.       final DefaultHttpClient httpClient = new DefaultHttpClient();  
  50.   
  51.       HttpGet hg = new HttpGet(url);  
  52.       HttpResponse httpResponse = httpClient.execute(hg);  
  53.       if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  
  54.         bmp = BitmapFactory.decodeStream(httpResponse.getEntity().getContent());  
  55.         hg.abort();  
  56.       }  
  57.     }   
  58.     catch (ClientProtocolException e) {}   
  59.     catch (IOException e) {}  
  60.   }  
  61. }  


Logcat の出力の一部

  1. D/StrictMode(  387): StrictMode policy violation; ~duration=1456 ms: android.os.StrictMode$StrictModeNetworkViolation: policy=23 violation=4  
  2. D/StrictMode(  387):  at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:758)  
  3. D/StrictMode(  387):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:774)  
  4. D/StrictMode(  387):  at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:103)  
  5. D/StrictMode(  387):  at org.apache.http.impl.io.AbstractSessionInputBuffer.read(AbstractSessionInputBuffer.java:134)  
  6. D/StrictMode(  387):  at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:174)  
  7. D/StrictMode(  387):  at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:188)  
  8. D/StrictMode(  387):  at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:178)  
  9. D/StrictMode(  387):  at java.io.BufferedInputStream.fillbuf(BufferedInputStream.java:140)  
  10. D/StrictMode(  387):  at java.io.BufferedInputStream.read(BufferedInputStream.java:324)  
  11. D/StrictMode(  387):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)  
  12. D/StrictMode(  387):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:460)  
  13. D/StrictMode(  387):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:515)  
  14. D/StrictMode(  387):  at yanzm.example.strictmodesample.MyActivity.downloadFromInternet(MyActivity.java:49)  
  15. D/StrictMode(  387):  at yanzm.example.strictmodesample.MyActivity.onCreate(MyActivity.java:34)  
  16. D/StrictMode(  387):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)  
  17. D/StrictMode(  387):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586)  
  18. D/StrictMode(  387):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638)  
  19. D/StrictMode(  387):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)  
  20. D/StrictMode(  387):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)  
  21. D/StrictMode(  387):  at android.os.Handler.dispatchMessage(Handler.java:99)  
  22. D/StrictMode(  387):  at android.os.Looper.loop(Looper.java:123)  
  23. D/StrictMode(  387):  at android.app.ActivityThread.main(ActivityThread.java:3647)  
  24. D/StrictMode(  387):  at java.lang.reflect.Method.invokeNative(Native Method)  
  25. D/StrictMode(  387):  at java.lang.reflect.Method.invoke(Method.java:507)  
  26. D/StrictMode(  387):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)  
  27. D/StrictMode(  387):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)  
  28. D/StrictMode(  387):  at dalvik.system.NativeStart.main(Native Method)  




 

0 件のコメント:

コメントを投稿