Question

Today I faced with a strange issue. I installed my application on three devices

  1. Asus Transformer Pad Infinity TF700T
  2. Samsung I9082 Galaxy Grand Duos
  3. LG Optimus L7 II Dual p715

First, I ran my app from Eclipse in the Debug mode with all of these devices. And it's ok.

Then, I ran my app in usual way (right on devices). And in this way all my bad have been started. For 1 and 2 devices all ok. But 3 device didn't work as I expected. The LogCat showed me the following fatal error:

01-14 01:36:47.529: E/dalvikvm(11294): threadid=1: stuck on threadid=14, giving up 01-14 01:36:47.529: A/libc(11294): Fatal signal 16 (SIGSTKFLT) at 0x00002c1e (code=-6), thread 11315 (AsyncTask #4)

I really cannot understand, what's going on and why both 1 and 2 devices work properly, but third doesn't.

Could anyone explain me, what this error means and how this can be corrected?

UPD1 I do not use NDK calls and any third-party libraries.

UPD2 The big code snippet that caused an error is(I include here all events invoke the draw process and stop it):

//I included all imports for sure that I don't use nothing instead of standard things
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.WindowManager;

public class MyLiveWallpaper extends WallpaperService {
    public static final String CONFIGS = "configs";
    private WallpaperEngine we;

    @Override
    public void onCreate() {
            super.onCreate();
    }

    @Override
    public void onDestroy() {
            super.onDestroy();
            if(we.myDrawTask!=null){
                    we.myDrawTask.cancel(false);
            }
    }

    @Override
    public Engine onCreateEngine() {
            we = new WallpaperEngine();
            return we;
    }

    //DeviceScreenSize is some class where I just incapsulate screen width, height and depth obtained in getScreenSize() method
    DeviceScreenSize dss = new DeviceScreenSize(0, 0, 0);

    class WallpaperEngine extends Engine implements
                    OnSharedPreferenceChangeListener {
            //Some definitions below
            ............................
            public DrawTask myDrawTask = null;
            ............................
            //Some definitions above

            WallpaperEngine() {
                    ..............
                    doubleTapDetector = new GestureDetector(HDLiveWallpaper.this,
                                    new SimpleOnGestureListener() {
                            @Override
                            public boolean onDoubleTap(MotionEvent e) {
                                    if (mTouchEvents) {
                                            mLastDrawTime = 0;
                                            if(myDrawTask!=null){
                                                    myDrawTask.stopAnimationFlag = true;
                                            }
                                            else{
                                                    myDrawTask = new DrawTask(getSurfaceHolder(), mPaint);
                                                    myDrawTask.execute();
                                            }
                                            return true;
                                    }
                                    return false;
                            }
                    });
            }

            @Override
            public void onCreate(SurfaceHolder surfaceHolder) {
                    super.onCreate(surfaceHolder);
                    // Register receiver for media events
                    IntentFilter filter = new IntentFilter();
                    filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
                    filter.addAction(Intent.ACTION_MEDIA_CHECKING);
                    filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
                    filter.addAction(Intent.ACTION_MEDIA_EJECT);
                    filter.addAction(Intent.ACTION_MEDIA_NOFS);
                    filter.addAction(Intent.ACTION_MEDIA_REMOVED);
                    filter.addAction(Intent.ACTION_MEDIA_SHARED);
                    filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
                    filter.addDataScheme("file");
                    mReceiver = new BroadcastReceiver() {
                            @Override
                            public void onReceive(Context context, Intent intent) {
                                    String action = intent.getAction();
                                    if (action.equals(Intent.ACTION_MEDIA_MOUNTED) || action.equals(Intent.ACTION_MEDIA_CHECKING)) {
                                            mStorageReady = true;
                                            setTouchEventsEnabled(true);

                                            if(myDrawTask!=null){
                                                    myDrawTask.cancel(false);
                                            }
                                            myDrawTask = new DrawTask(getSurfaceHolder(), mPaint);
                                            myDrawTask.execute();

                                    } else {
                                            mStorageReady = false;
                                            setTouchEventsEnabled(false);
                                            if(myDrawTask!=null) myDrawTask.cancel(false);
                                    }
                            }
                    };
                    registerReceiver(mReceiver, filter);

                    // Register receiver for screen on events
                    mScreenOnReciever = new BroadcastReceiver() {
                            @Override
                            public void onReceive(Context context, Intent intent) {
                                    System.out.println(Intent.ACTION_SCREEN_ON);
                                    if (mScreenWake) {
                                            mLastDrawTime = 0;
                                    }
                                    if(myDrawTask!=null){
                                            myDrawTask.cancel(false);
                                    }
                                    myDrawTask = new DrawTask(getSurfaceHolder(), mPaint);
                                    myDrawTask.execute();
                            }
                    }; 
                    registerReceiver(mScreenOnReciever, new IntentFilter(Intent.ACTION_SCREEN_ON));

                    mScreenOffReciever = new BroadcastReceiver() {
                            @Override
                            public void onReceive(Context context, Intent intent) {
                                    System.out.println(Intent.ACTION_SCREEN_OFF);
                                    if (mScreenWake) {
                                            mLastDrawTime = 0;
                                    }
                                    if(myDrawTask!=null){
                                            myDrawTask.cancel(false);
                                    }
                            }
                    }; 
                    registerReceiver(mScreenOffReciever, new IntentFilter(Intent.ACTION_SCREEN_OFF));

                    setTouchEventsEnabled(mStorageReady);
            }

            @Override
            public void onDestroy() {
                    super.onDestroy();
                    mPrefs.unregisterOnSharedPreferenceChangeListener(this);
                    unregisterReceiver(mReceiver);
                    unregisterReceiver(mScreenOnReciever);
                    unregisterReceiver(mScreenOffReciever);
                    if(myDrawTask!=null){
                            myDrawTask.cancel(false);
                    }
            }

            @Override
            public void onVisibilityChanged(boolean visible) {
                    mVisible = visible;
                    if (visible) {
                            if(myDrawTask!=null){
                                    myDrawTask.cancel(false);
                            }
                            myDrawTask = new DrawTask(getSurfaceHolder(), mPaint);
                            myDrawTask.execute();
                            mLastDrawTime = 0;
                    } else {
                            if(myDrawTask!=null){
                                    myDrawTask.cancel(false);
                            }
                    }
            }

            @Override
            public void onSurfaceChanged(SurfaceHolder holder, int format,
            int width, int height) {
                    super.onSurfaceChanged(holder, format, width, height);
                    .....................
                    if (mBitmap != null) {
                            mBitmap.recycle();
                    }

                    if(myDrawTask!=null){
                            myDrawTask.cancel(false);
                    }
                    myDrawTask = new DrawTask(getSurfaceHolder(), mPaint);
                    myDrawTask.execute();
            }

            @Override
            public void onSurfaceCreated(SurfaceHolder holder) {
                    super.onSurfaceCreated(holder);
                    if(myDrawTask!=null){
                            myDrawTask.cancel(false);
                    }
                    myDrawTask = new DrawTask(getSurfaceHolder(), mPaint);
                    myDrawTask.execute();
                    mLastDrawTime = 0;
            }

            @Override
            public void onSurfaceDestroyed(SurfaceHolder holder) {
                    super.onSurfaceDestroyed(holder);
                    mVisible = false;
                    if(myDrawTask!=null){
                            myDrawTask.cancel(false);
                    }
            }

            @Override
            public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
            float yStep, int xPixels, int yPixels) {
                    mXOffset = xOffset;
                    mYOffset = yOffset;
                    if(myDrawTask!=null){
                            myDrawTask.cancel(false);
                    }
                    myDrawTask = new DrawTask(getSurfaceHolder(), mPaint);
                    myDrawTask.execute();
            }

            @Override
            public void onTouchEvent(MotionEvent event) {
                    super.onTouchEvent(event);
                    this.doubleTapDetector.onTouchEvent(event);
            }

            public final Bitmap drawableToBitmap(Drawable drawable) {
                    int targetWidth = (mScroll) ? mMinWidth : dss.getWidth();
                    int targetHeight = (mScroll) ? mMinHeight : dss.getHeight();

                    Bitmap bitmap = Bitmap.createBitmap(targetWidth, targetHeight, Config.ARGB_8888);

                    Canvas canvas = new Canvas(bitmap);
                    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                    drawable.draw(canvas);

                    // Rotate
                    .....................

                    // Scale bitmap
                    .....................
                    return bitmap;
            }

            void getScreenSize() {
                    WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
                    Display d = wm.getDefaultDisplay();
                    DisplayMetrics metrics = new DisplayMetrics();
                    d.getMetrics(metrics);

                    // since SDK_INT = 1;
                    dss.setDeviceScreenParams(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);

                    // includes window decorations (statusbar bar/menu bar)
                    if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)
                            try {
                                    dss.setDeviceScreenParams((Integer) Display.class.getMethod("getRawWidth").invoke(d), (Integer) Display.class.getMethod("getRawHeight").invoke(d), metrics.densityDpi);
                            } catch (Exception ignored) {}

                    // includes window decorations (statusbar bar/menu bar)
                    if (Build.VERSION.SDK_INT >= 17)
                            try {
                                    DisplayMetrics realSize = new DisplayMetrics();
                                    Display.class.getMethod("getRealMetrics", DisplayMetrics.class).invoke(d, realSize);
                                    dss.setDeviceScreenParams(realSize.widthPixels, realSize.heightPixels, realSize.densityDpi);
                            } catch (Exception ignored) {}
            }

            //
            // ************************
            // DRAW AND ANIMATION TASK
            // ************************
            //
            public class DrawTask extends AsyncTask<Void, Void, Void> {
                    private final SurfaceHolder _surfaceHolder;
                    private Paint myPaint;
                    boolean CancelFlag = false, stopAnimationFlag = false;

                    //HANDLERS
                    private final Handler mDrawHandler = new Handler(){
                            public void handleMessage(android.os.Message msg) { };
                    };

                    //WORKERS
                    private final Runnable mDrawWorker = new Runnable() {
                            public void run() {
                                    if (mDuration > 0)
                                    {
                                            drawFrame();
                                    }
                            }
                    };

                    DrawTask(SurfaceHolder holder, Paint paint){
                            _surfaceHolder = holder;
                            myPaint = paint;
                            CancelFlag = false;
                    }

                    SurfaceHolder getSurfHolder(){
                            return _surfaceHolder;
                    }

                    Paint getPaint(){
                            return myPaint;
                    }

                    @Override
                    protected void onPreExecute() {
                            super.onPreExecute();
                    }   

                    @Override
                    protected Void doInBackground(Void... params) {
                            drawFrame();
                            while(!CancelFlag){}
                            return null;
                    }

                    @Override
                    protected void onPostExecute(Void result) {
                            // TODO Auto-generated method stub
                            super.onPostExecute(result);
                    }

                    @Override
                    protected void onCancelled() {
                            // TODO Auto-generated method stub
                            super.onCancelled();
                            CancelFlag = true;
                    }

                    void drawFrame() {
                            final SurfaceHolder holder = _surfaceHolder;
                            Canvas c = null;
                            boolean getImage = false;

                            try {
                                    // Lock the canvas for writing
                                    c = holder.lockCanvas();

                                    // Do we need to get a new image?
                                    if (mBitmap == null) {
                                            getImage = true;
                                    } else if (mDuration > 0 && mLastDrawTime < System.currentTimeMillis() - mDuration) {
                                            getImage = true;
                                    } else if (mLastDrawTime == 0) {
                                            getImage = true;
                                    }

                                    // Get image to draw
                                    if (getImage) {
                                            // Get a list of files
                                            String[] assets_files = null;
                                            try {
                                                    assets_files = getApplicationContext().getAssets().list("");
                                            } catch (IOException e) {
                                                    e.printStackTrace();
                                            }

                                            List<String> str_list = new ArrayList<String>();
                                            for (int fi = 0; fi < assets_files.length; fi++) {
                                                    String ext = BitmapUtil.getExtension(assets_files[fi]);
                                                    if (ext != null) {
                                                            if (ext.equals("jpg") || ext.equals("jpeg") || ext.equals("png") || ext.equals("gif")) {
                                                                    str_list.add(assets_files[fi]);
                                                            }
                                                    }
                                            }
                                            assets_files = str_list.toArray(new String[str_list.size()]);

                                            // Increment counter
                                            int nFiles = assets_files.length;
                                            if (mRandom) {
                                                    int i = mIndex;
                                                    do {
                                                            mIndex = (int) (Math.random() * nFiles);
                                                    } while (nFiles > 1 && mIndex == i);
                                            } else {
                                                    if (++mIndex >= nFiles) {
                                                            mIndex = 0;
                                                    }
                                            }

                                            InputStream ims = null;
                                            try {
                                                    ims = getAssets().open(assets_files[mIndex]);
                                            } catch (IOException e) {
                                                    e.printStackTrace();
                                            }
                                            d = Drawable.createFromStream(ims, null);

                                            // Read file to bitmap
                                            mBitmap=null;
                                            mBitmap = drawableToBitmap(d);

                                            // Save the current time
                                            mLastDrawTime = System.currentTimeMillis();
                                    } else if (mBitmap != null && mBitmap.isRecycled()){
                                            mBitmap=null;
                                            mBitmap = drawableToBitmap(d);
                                    }
                            } catch (NullPointerException npe) {
                                    holder.unlockCanvasAndPost(c);
                                    return;
                            } catch (RuntimeException re) {
                                    holder.unlockCanvasAndPost(c);
                                    return;
                            }

                            try {
                                    if (c != null) {
                                            int xPos;
                                            int yPos;
                                            if (mScroll) {
                                                    xPos = 0 - (int) (mWidth * mXOffset);
                                                    yPos = 0 - (int) (mHeight * mYOffset);
                                            } else {
                                                    xPos = 0;
                                                    yPos = 0;
                                            }
                                            try {
                                                    c.drawColor(Color.BLACK);
                                                    c.drawBitmap(mBitmap, xPos, yPos, myPaint);        
                                            } catch (Throwable t) {}
                                    }
                            } finally {
                                    if (c != null){
                                            if((mPreviousBitmap==null) || (mPreviousBitmap==mBitmap))
                                                    holder.unlockCanvasAndPost(c);
                                            else{                       
                                                    if(mTransition!=0)
                                                            startAnimation(mTransition, holder, c);
                                                    else
                                                            holder.unlockCanvasAndPost(c);
                                            }
                                                    mPreviousBitmap=null;
                                                    mPreviousBitmap = mBitmap;
                                    }
                            }

                            // Reschedule the next redraw
                            mDrawHandler.removeCallbacks(mDrawWorker);

                            if (mVisible) {
                                    mDrawHandler.postDelayed(mDrawWorker, 1000 / 2);
                            }
                            else{CancelFlag=true;}
                    }



                    void startAnimation(int animNumber, SurfaceHolder holder, Canvas canvas)
                    {
                            switch(animNumber){
                                    case 1:{
                                            canvas.drawBitmap(mBitmap, 0, 0, myPaint);
                                            int tmpPaintAlpha = myPaint.getAlpha();
                                            myPaint.setAlpha(255);
                                            canvas.drawBitmap(mPreviousBitmap, 0, 0, myPaint);
                                            holder.unlockCanvasAndPost(canvas);
                                            myPaint.setAlpha(tmpPaintAlpha);

                                            int i=224;
                                            while(i>=0){
                                                    canvas = holder.lockCanvas();
                                                    canvas.drawBitmap(mBitmap, 0, 0, myPaint);
                                                    myPaint.setAlpha(i);
                                                    canvas.drawBitmap(mPreviousBitmap, 0, 0, myPaint);
                                                    holder.unlockCanvasAndPost(canvas);
                                                    myPaint.setAlpha(255);
                                                    i-=18;
                                            }
                                            mLastDrawTime=System.currentTimeMillis();
                                            break;
                                    }
                                    case 2:{
                                            ....................
                                            break;
                                    }
                            }
                    }
            }
    ...................
    }
    ...................
}

Here the error occures every time when we fall in the DrawTask.drawFrame() method even without any anymations (mTransition==0). And as the result I see:

(1) First step with initial image and next image is done properly;

(2) When it's time to change second to third etc. images, I just see the black screen during not constant period, and then I see again my initial image and repeat all in (2) infinitely. Any changes of settings don't change this behaviour.

UPD3 Hope my detailed descriptions(UPD1, UPD2) of this issue can help to find a reason of this strange behaviour. But, unfortunately, not for me now.

Big thanks in advance!

Was it helpful?

Solution

SIGSTKFLT happens when the device runs out of memory, esp. when using malloc() calls in the underlying linux OS layer. When the OS cannot return a fail in malloc, it generates a fatal signal of this kind.

Try using some memory saving techniques(like late binding image decoding) to fix the above issues on low memory devices, when dealing with images as they occupy a lot of memory.

For a start, You can try re-sizing the image to the screen resolution or lower, before posting it to the canvas.

OTHER TIPS

Thanks everybody for supporting me! I found true cause of my problem. It was just a stupid approach to an issue of correct threading. The sequence of events invoked, for example, on start, was the following:

WallpaperService.onCreate()

onSharedPreferenceChanged()

WallpaperService.onCreateEngine()

Engine.onCreate()

Engine.onSurfaceCreated() (here DrawTask #1 was created)

Engine.onSurfaceChanged() (here DrawTask #2 was created)

Engine.onVisibilityChanged() (here DrawTask #3 was created)

Engine.onOffsetChanged() (here DrawTask #4 was created)

Engine.onOffsetChanged() (here DrawTask #5 was created)

Engine.onOffsetChanged() (here DrawTask #6 was created)

Engine.onOffsetChanged() (here DrawTask #7 was created)

Engine.onOffsetChanged() (here DrawTask #8 was created)

Engine.onOffsetChanged() (here DrawTask #9 was created)

Engine.onOffsetChanged() (here DrawTask #10 was created)

Engine.onOffsetChanged() (here DrawTask #11 was created)

Engine.onOffsetChanged() (here DrawTask #12 was created)

Engine.onOffsetChanged() (here DrawTask #13 was created)

DrawTask #2 was stopped

DrawTask #3 was stopped

DrawTask #4 was stopped

DrawTask #6 was stopped

DrawTask #5 was stopped ...

So, I removed all AsyncTask generation overall, except onVisibilityChanged() and onSurfaceChanged() if variable mVisible is true. And now it's OK at least for all of my devices.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top