致命信号 16 (SIGSTKFLT) 意外发生

Posted

技术标签:

【中文标题】致命信号 16 (SIGSTKFLT) 意外发生【英文标题】:Fatal signal 16 (SIGSTKFLT) has been occured unexpectedly 【发布时间】:2014-01-14 00:36:20 【问题描述】:

今天我遇到了一个奇怪的问题。 我在三台设备上安装了我的应用程序

    华硕Transformer Pad Infinity TF700T 三星 I9082 Galaxy Grand Duos LG Optimus L7 II Dual p715

首先,我使用所有这些设备在调试模式下从 Eclipse 运行我的应用程序。而且没关系。

然后,我以通常的方式运行我的应用程序(直接在设备上)。就这样,我所有的坏事都开始了。对于 1 和 2 设备都可以。但是 3 设备没有像我预期的那样工作。 LogCat 向我显示了以下致命错误:

01-14 01:36:47.529: E/dalvikvm(11294): threadid=1: 卡住 threadid=14,放弃 01-14 01:36:47.529: A/libc(11294): 致命信号 16 (SIGSTKFLT) 在 0x00002c1e (code=-6),线程 11315 (AsyncTask #4)

我真的不明白,发生了什么以及为什么 1 和 2 设备都可以正常工作,但第三个却不能。

谁能解释一下,这个错误是什么意思以及如何纠正?

UPD1我不使用 NDK 调用和任何第三方库。

UPD2导致错误的大代码sn-p是(我在这里包括所有事件调用绘制过程并停止它):

//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);
                            
                            elseCancelFlag=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;
                                    
                            
                    
            
    ...................
    
    ...................

这里每次我们陷入 DrawTask.drawFrame() 方法时都会发生错误,即使没有任何信息 (mTransition==0)。结果我看到了:

(1) 初始图像的第一步和下一个图像正确完成;

(2) 当需要更改第二到第三个等图像时,我只是在非恒定时间段内看到黑屏,然后我再次看到我的初始图像并无限重复 (2) 中的所有内容。任何设置更改都不会改变此行为。

UPD3希望我对此问题的详细描述(UPD1、UPD2)可以帮助找到这种奇怪行为的原因。但是,不幸的是,现在不适合我。

非常感谢!

【问题讨论】:

您在使用 NDK 吗?或者,您是否使用任何包含 NDK 编译代码的第三方库? 您的应用程序崩溃时在做什么?可以看到“libc”,这是底层C++系统代码的崩溃。 我不使用 NDK 或任何其他第三方库。只是一个标准的东西是我逻辑的一部分。该代码是一种简单的动态壁纸,用于在更改事件(按时间、双击或任何其他动作)上以不同的动画幻灯片显示不同的图像。我传递给 AsyncTask 的绘图和动画部分。您可以在上面的 UPD2 部分中看到导致错误的代码。我包括 big sn-p 以便更好地澄清(但直接问题最终出现 - 在 DrawTask.drawFrame() 方法中)。 【参考方案1】:

SIGSTKFLT 在设备内存不足时发生,尤其是。在底层 linux OS 层中使用 malloc() 调用时。当操作系统无法在 malloc 中返回失败时,它会生成此类致命信号。

尝试使用一些节省内存的技术(如后期绑定图像解码)来解决内存不足的设备上的上述问题,因为它们会占用大量内存。

首先,您可以尝试将图像调整为屏幕分辨率或更低,然后再将其发布到画布上。

【讨论】:

但在我看来,我在方法 drawableToBitmap() 中调整图像的大小,并在方法 getScreenSize() 中接收到屏幕宽度和高度。为此,我在转换为位图之前使用方法 drawable.setBounds()。这是正确的吗?或者我应该以另一种方式做到这一点?顺便说一句,即使使用 48x48 图像,我也尝试了我的应用程序并得到了相同的行为。 在上面的代码中,在一些速度较慢的设备上,您可以长时间握住画布。看,这个调用: c = holder.lockCanvas();并且您正在处理要显示的数据,然后解锁画布尝试在异步任务或其他内容中进行所有处理,然后调用drawFrame(),更新画布然后解锁它。例如:updateScreen() processFrame(); // 在此处添加所有帧处理 drawFrame(); drawFrame() // 获取并锁定画布 // 在画布上绘制 -> 仅绘制,此处不处理 // 解锁并发布 【参考方案2】:

感谢大家对我的支持!我找到了问题的真正原因。这只是解决正确线程问题的一种愚蠢方法。例如,在开始时调用的事件顺序如下:

WallpaperService.onCreate()

onSharedPreferenceChanged()

WallpaperService.onCreateEngine()

Engine.onCreate()

Engine.onSurfaceCreated()(这里创建了 DrawTask #1)

Engine.onSurfaceChanged()(这里创建了 DrawTask #2)

Engine.onVisibilityChanged()(这里创建了 DrawTask #3)

Engine.onOffsetChanged()(这里创建了 DrawTask #4)

Engine.onOffsetChanged()(这里创建了 DrawTask #5)

Engine.onOffsetChanged()(这里创建了 DrawTask #6)

Engine.onOffsetChanged()(这里创建了 DrawTask #7)

Engine.onOffsetChanged()(这里创建了 DrawTask #8)

Engine.onOffsetChanged()(这里创建了 DrawTask #9)

Engine.onOffsetChanged()(这里创建了 DrawTask #10)

Engine.onOffsetChanged()(这里创建了 DrawTask #11)

Engine.onOffsetChanged()(这里创建了 DrawTask #12)

Engine.onOffsetChanged()(这里创建了 DrawTask #13)

DrawTask #2 已停止

DrawTask #3 已停止

DrawTask #4 已停止

DrawTask #6 已停止

DrawTask #5 已停止 ...

因此,如果变量 mVisible 为 true,则我删除了所有 AsyncTask 生成,除了 onVisibilityChanged() 和 onSurfaceChanged()。现在至少我的所有设备都可以了。

【讨论】:

以上是关于致命信号 16 (SIGSTKFLT) 意外发生的主要内容,如果未能解决你的问题,请参考以下文章

@IBInspectable 致命错误:在展开可选值时意外发现 nil

Swift 物理致命错误:当两个字符发生碰撞时,在展开可选值时意外发现 nil

Swift 错误致命错误:在展开可选值时意外发现 nil

信号驱动I/O详解

信号_Linux下常用的信号有哪些

Linux 信号:signal 与 sigaction