`IllegalArgumentException: width and height must be > 0` によるBitmap生成時のクラッシュについて

クラッシュログをみていると、稀に表題のような例外が出てdrawableリソースの生成に失敗したりlayout XMLの構築に失敗するクラッシュがありました。昔からある程度発生していたものの数が少ないので無視していたのですが、最近他のクラッシュを直していった結果相対的に目立ってきたので詳しく調べたところ、原因がわかったので記録しておきます。

結論からいうとこれはAndroid frameworkのバグで、特定の条件をみたすときに `Bitmap.createBitmap()` の引数に渡されるwidthないしheightが0になるというもののようでした。

原理としては、高解像度用の画像リソース（e.g. `drawable-xhdpi`）のみを提供しているとき低解像度端末ではこれを縮小して使うのですが、一辺が1pxの画像だと50%未満に縮小することがあり、結果その一辺が0pxになってしまうということのようです。

したがって、 **hdpi用の画像リソースを用意** すればこの計算で一辺が0pxになることはなく、クラッシュを回避できます。

クラッシュが確認できる条件は以下のとおりです。ただし、これ以外の条件でもクラッシュは起きているので、他にも何か条件があるのかもしれません。

* Android 4.0.3 以下
    * emulatorでのみ確認済み
* ldpi端末である
* ある一辺のサイズが3px以下の9-patch pngがある
    * この画像のdrawable-hdpi以下のdpi用のリソースがない
    * 9-patchは外側の1pxがマーカーエリアなので、これは実質1pxの画像

reproducable project: 

* https://github.com/gfx/LdpiResourceNotFoundOnLdpi
    * ldpi & ICSなデバイスだと起動直後にクラッシュするはず

cf. [Android resource not found because of width and height - Stack Overflow](http://stackoverflow.com/questions/15428441/android-resource-not-found-because-of-width-and-height)

full stacktrace:

```
05-16 12:13:05.887    1698-1698/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.github.gfx.resourcenotfoundonldpi/com.github.gfx.resourcenotfoundonldpi.MainActivity}: android.view.InflateException: Binary XML file line #17: Error inflating class android.widget.ImageView
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
            at android.app.ActivityThread.access$600(ActivityThread.java:123)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4424)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: android.view.InflateException: Binary XML file line #17: Error inflating class android.widget.ImageView
            at android.view.LayoutInflater.createView(LayoutInflater.java:606)
            at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
            at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
            at com.github.gfx.resourcenotfoundonldpi.MainActivity.onCreate(MainActivity.java:14)
            at android.app.Activity.performCreate(Activity.java:4465)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
            at android.app.ActivityThread.access$600(ActivityThread.java:123)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4424)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.reflect.InvocationTargetException
            at java.lang.reflect.Constructor.constructNative(Native Method)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
            at android.view.LayoutInflater.createView(LayoutInflater.java:586)
            at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
            at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
            at com.github.gfx.resourcenotfoundonldpi.MainActivity.onCreate(MainActivity.java:14)
            at android.app.Activity.performCreate(Activity.java:4465)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
            at android.app.ActivityThread.access$600(ActivityThread.java:123)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4424)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: android.content.res.Resources$NotFoundException: File res/drawable-xxhdpi-v4/image.9.png from drawable resource ID #0x7f02003b
            at android.content.res.Resources.loadDrawable(Resources.java:1940)
            at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
            at android.widget.ImageView.<init>(ImageView.java:119)
            at android.widget.ImageView.<init>(ImageView.java:109)
            at java.lang.reflect.Constructor.constructNative(Native Method)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
            at android.view.LayoutInflater.createView(LayoutInflater.java:586)
            at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
            at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
            at com.github.gfx.resourcenotfoundonldpi.MainActivity.onCreate(MainActivity.java:14)
            at android.app.Activity.performCreate(Activity.java:4465)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
            at android.app.ActivityThread.access$600(ActivityThread.java:123)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4424)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.IllegalArgumentException: width and height must be > 0
            at android.graphics.Bitmap.createBitmap(Bitmap.java:603)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
            at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:437)
            at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:524)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:499)
            at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351)
            at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:773)
            at android.content.res.Resources.loadDrawable(Resources.java:1935)
            at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
            at android.widget.ImageView.<init>(ImageView.java:119)
            at android.widget.ImageView.<init>(ImageView.java:109)
            at java.lang.reflect.Constructor.constructNative(Native Method)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
            at android.view.LayoutInflater.createView(LayoutInflater.java:586)
            at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
            at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
            at com.github.gfx.resourcenotfoundonldpi.MainActivity.onCreate(MainActivity.java:14)
            at android.app.Activity.performCreate(Activity.java:4465)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
            at android.app.ActivityThread.access$600(ActivityThread.java:123)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4424)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
            at dalvik.system.NativeStart.main(Native Method)
```