2013-07-30 6 views
6

Una regressione è stata introdotta in Android 4.3. Il codice utilizzato nelle versioni precedenti di Android ora causa un arresto anomalo nativo che arresta il processo.Native Crash in Android 4.3 quando si chiama Picture.writeToStream()

L'arresto anomalo si verifica quando si disegna un'immagine che è maggiore di 32 kb in una tela che viene registrata da un oggetto Picture che viene a sua volta scritto in uno streaming tramite writeToStream().

Lo schianto si verifica in Skia quando si tenta di cancellare una stringa (che credo sia l'Uri dell'oggetto immagine).

I/DEBUG(122):  #00 pc 0001e3bc /system/lib/libc.so (strlen+72)  
I/DEBUG(122):  #01 pc 000d9858 /system/lib/libskia.so (SkWriter32::writeString(char const*, unsigned int)+256)  
I/DEBUG(122):  #02 pc 00113d68 /system/lib/libskia.so (SkImageRef_ashmem::flatten(SkFlattenableWriteBuffer&) const+44) 

Il seguente programma mostra come riprodurre questo problema. Tutto ciò che serve è un layout con un pulsante che ha il pulsante 'id'.

public class MainActivity extends Activity { 

    static final String IMAGE_FILE = Environment.getExternalStorageDirectory() + "/test.jpg"; 
    static final String SKIA_FILE = Environment.getExternalStorageDirectory() + "/test.skia"; 

    private static Bitmap loadBitmap(final String filename) { 
     Bitmap bitmap = null; 
     FileInputStream is; 
     try { 
      is = new FileInputStream(filename); 
      final BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.inInputShareable = true; 
      options.inPurgeable = true; 
      bitmap = BitmapFactory.decodeFileDescriptor(is.getFD(), null, options); 
      is.close(); 
     } catch (final FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (final IOException ex) { 
      ex.printStackTrace(); 
     } 
     return bitmap; 
    } 

    @Override 
    protected void onCreate(final Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     final Button button = (Button) findViewById(R.id.button); 
     button.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(final View v) { 

       final Runnable runnable = new Runnable() { 
        @Override 
        public void run() { 
         // Create a Canvas and begin recording 
         final Picture picture = new Picture(); 
         final Canvas canvas = picture.beginRecording(1024, 1024); 
         // De-compress an image from file 
         final Bitmap bitmap = loadBitmap(IMAGE_FILE); 
         // If present draw the image to the canvas and end 
         // recording 
         if (bitmap != null) { 
          canvas.drawBitmap(bitmap, new Matrix(), null); 
         } 
         picture.endRecording(); 

         // Write out the Picture object to a Skia File. 
         FileOutputStream os; 
         try { 
          os = new FileOutputStream(SKIA_FILE); 
          picture.writeToStream(os); 
          os.close(); 
         } catch (final FileNotFoundException e) { 
          e.printStackTrace(); 
         } catch (final IOException ex) { 
          ex.printStackTrace(); 
         } 
        } 
       }; 
       new Thread(runnable).start(); 
      } 
     }); 
    } 
} 

Le due linee di impostazione dei BitmapFactory.Options sono necessari per ottenere il codice appiattimento Skia per scrivere i dati di immagine (Altrimenti immagini vengono emessi).

options.inInputShareable = true; 
options.inPurgeable = true; 

Sono consapevole che i metodi Immagine writeToStream() e createFromStream() sono stati deprecati, ma non mi aspetto questo per introdurre un problema di stabilità.

Ho bisogno di cancellare l'oggetto Immagine come voglio passare dall'applicazione principale a un processo di servizio. Non posso usare la soluzione consigliata nella documentazione che dice a 'disegnare l'immagine in una bitmap' per i seguenti motivi:

  1. La risoluzione dell'immagine desiderata non è noto al momento della stesura di distanza.
  2. L'oggetto immagine deve essere ingrandito tramite una matrice dopo il ripristino.
  3. Il salvataggio in una bitmap ad altissima risoluzione è inefficiente in termini di memoria e tempo di elaborazione.

Qualcuno sa un lavoro che consente alle immagini di essere scritte nello stream senza causare questo arresto?

risposta

4

avrei aggiunto questo come un commento, ma mi manca la reputazione ...

Il cambiamento di rottura in Skia sembra essere la modifica SkImageRef_ashmem.cpp:

https://code.google.com/p/skia/source/detail?r=4980

Il metodo flatten utilizzato per verificare la presenza di un URI null e scriverebbe 0 sul flusso di output se l'uri fosse nullo. Passare null a SkFlattenableWriteBuffer::writeString() provoca l'arresto anomalo in strlen().

+1

Segnalato al progetto Skia come numero 1457: https://code.google.com/p/skia/issues/detail?id=1457 – CAB

+0

Questo dovrebbe essere corretto nella versione futura di Android ora come il nucleo del team di Skia ha controllato in una correzione, vedi https://code.google.com/p/android/issues/detail?id=58257 –