Repository: thundernest/k-9
Issue: Crash: OOM during migration

Via Play Developer Console
App version: 5.200

```
java.lang.OutOfMemoryError: Failed to allocate a 2060 byte allocation with 1974 free bytes and 1974B until OOM
	at org.apache.james.mime4j.stream.MimeEntity.advanceToBoundary(MimeEntity.java:387)
	at org.apache.james.mime4j.stream.MimeEntity.advance(MimeEntity.java:331)
	at org.apache.james.mime4j.stream.MimeTokenStream.next(MimeTokenStream.java:360)
	at org.apache.james.mime4j.parser.MimeStreamParser.parse(MimeStreamParser.java:176)
	at com.fsck.k9.mail.message.MessageHeaderParser.parse(MessageHeaderParser.java:24)
	at com.fsck.k9.mailstore.LocalMessage.populateFromGetMessageCursor(LocalMessage.java:127)
	at com.fsck.k9.mailstore.LocalStore$13.doDbWork(LocalStore.java:638)
	at com.fsck.k9.mailstore.LocalStore$13.doDbWork(LocalStore.java:615)
	at com.fsck.k9.mailstore.LockableDatabase.execute(LockableDatabase.java:275)
	at com.fsck.k9.mailstore.LocalStore.getMessages(LocalStore.java:615)
	at com.fsck.k9.mailstore.LocalFolder$10.doDbWork(LocalFolder.java:880)
	at com.fsck.k9.mailstore.LocalFolder$10.doDbWork(LocalFolder.java:875)
	at com.fsck.k9.mailstore.LockableDatabase.execute(LockableDatabase.java:275)
	at com.fsck.k9.mailstore.LocalFolder.getMessages(LocalFolder.java:875)
	at com.fsck.k9.mailstore.migrations.MigrationTo55.createFtsSearchTable(MigrationTo55.java:36)
	at com.fsck.k9.mailstore.migrations.Migrations.upgradeDatabase(Migrations.java:66)
	at com.fsck.k9.mailstore.StoreSchemaDefinition.upgradeDatabase(StoreSchemaDefinition.java:60)
	at com.fsck.k9.mailstore.StoreSchemaDefinition.doDbUpgrade(StoreSchemaDefinition.java:36)
	at com.fsck.k9.mailstore.LockableDatabase.openOrCreateDataspace(LockableDatabase.java:381)
	at com.fsck.k9.mailstore.LockableDatabase.open(LockableDatabase.java:354)
	at com.fsck.k9.mailstore.LocalStore.<init>(LocalStore.java:210)
	at com.fsck.k9.mailstore.LocalStore.getInstance(LocalStore.java:235)
	at com.fsck.k9.Account.getLocalStore(Account.java:1278)
	at com.fsck.k9.controller.MessagingController.setupPushing(MessagingController.java:4322)
	at com.fsck.k9.service.MailService.setupPushers(MailService.java:349)
	at com.fsck.k9.service.MailService.reschedulePushers(MailService.java:338)
	at com.fsck.k9.service.MailService.access$100(MailService.java:24)
	at com.fsck.k9.service.MailService$1.run(MailService.java:194)
	at com.fsck.k9.service.CoreService$1.run(CoreService.java:315)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
	at java.lang.Thread.run(Thread.java:818)
```

Changed files:
k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java, k9mail/src/main/java/com/fsck/k9/mailstore/migrations/MigrationTo55.java

diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
index e9458479a..9cd8f2319 100644
--- a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
+++ b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
@@ -896,6 +896,42 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
         }
     }
 
+    public List<String> getAllMessageUids() throws MessagingException {
+        try {
+            return  localStore.database.execute(false, new DbCallback<List<String>>() {
+                @Override
+                public List<String> doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
+                    Cursor cursor = null;
+                    ArrayList<String> result = new ArrayList<>();
+
+                    try {
+                        open(OPEN_MODE_RO);
+
+                        cursor = db.rawQuery(
+                                "SELECT uid " +
+                                    "FROM messages " +
+                                        "WHERE empty = 0 AND deleted = 0 AND " +
+                                        "folder_id = ? ORDER BY date DESC",
+                                new String[] { Long.toString(mFolderId) });
+
+                        while (cursor.moveToNext()) {
+                            String uid = cursor.getString(0);
+                            result.add(uid);
+                        }
+                    } catch (MessagingException e) {
+                        throw new WrappedException(e);
+                    } finally {
+                        Utility.closeQuietly(cursor);
+                    }
+
+                    return result;
+                }
+            });
+        } catch (WrappedException e) {
+            throw(MessagingException) e.getCause();
+        }
+    }
+
     public List<LocalMessage> getMessagesByUids(@NonNull List<String> uids) throws MessagingException {
         open(OPEN_MODE_RW);
         List<LocalMessage> messages = new ArrayList<>();
diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/migrations/MigrationTo55.java b/k9mail/src/main/java/com/fsck/k9/mailstore/migrations/MigrationTo55.java
index 4f8f7e5dc..e9fb197ab 100644
--- a/k9mail/src/main/java/com/fsck/k9/mailstore/migrations/MigrationTo55.java
+++ b/k9mail/src/main/java/com/fsck/k9/mailstore/migrations/MigrationTo55.java
@@ -1,9 +1,7 @@
 package com.fsck.k9.mailstore.migrations;
 
 
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 
 import android.content.ContentValues;
@@ -20,8 +18,8 @@ import com.fsck.k9.mailstore.LocalStore;
 import com.fsck.k9.message.extractors.MessageFulltextCreator;
 
 
-public class MigrationTo55 {
-    public static void createFtsSearchTable(SQLiteDatabase db, MigrationsHelper migrationsHelper) {
+class MigrationTo55 {
+    static void createFtsSearchTable(SQLiteDatabase db, MigrationsHelper migrationsHelper) {
         db.execSQL("CREATE VIRTUAL TABLE messages_fulltext USING fts4 (fulltext)");
 
         LocalStore localStore = migrationsHelper.getLocalStore();
@@ -33,13 +31,11 @@ public class MigrationTo55 {
             FetchProfile fp = new FetchProfile();
             fp.add(FetchProfile.Item.BODY);
             for (LocalFolder folder : folders) {
-                Iterator<LocalMessage> localMessages = new ArrayList<>(folder.getMessages(null, false)).iterator();
-                while (localMessages.hasNext()) {
-                    LocalMessage localMessage = localMessages.next();
-                    // The LocalMessage objects are heavy once they have been loaded, so we free them asap
-                    localMessages.remove();
-
+                List<String> messageUids = folder.getAllMessageUids();
+                for (String messageUid : messageUids) {
+                    LocalMessage localMessage = folder.getMessage(messageUid);
                     folder.fetch(Collections.singletonList(localMessage), fp, null);
+
                     String fulltext = fulltextCreator.createFulltext(localMessage);
                     if (!TextUtils.isEmpty(fulltext)) {
                         Log.d(K9.LOG_TAG, "fulltext for msg id " + localMessage.getId() + " is " + fulltext.length() + " chars long");