Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03bd302a authored by Jeff Brown's avatar Jeff Brown
Browse files

Don't close the database until all references released.

SQLiteDatabase.close() should call releaseReference() rather than
closing the database immediately.  SQLiteDatabase should also hold
a reference to itself while performing certain operations to
ensure that they complete normally even if another thread closes
the database at the same time.

Fixed a couple of missing or redundant uses of acquireReference()
related to CursorWindows.

To be honest, the reference counting performed by SQLiteClosable should
not be needed, but we're stuck with it in the API.

Bug: 6104842
Change-Id: I3444a697409905d4a36b56418dc7766f5ba76b59
parent b4827c08
Loading
Loading
Loading
Loading
+5 −7
Original line number Diff line number Diff line
@@ -6904,7 +6904,7 @@ package android.database {
    method public boolean onMove(int, int);
  }
  public abstract interface Cursor {
  public abstract interface Cursor implements java.io.Closeable {
    method public abstract void close();
    method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
    method public abstract deprecated void deactivate();
@@ -6977,7 +6977,6 @@ package android.database {
    ctor public deprecated CursorWindow(boolean);
    method public boolean allocRow();
    method public void clear();
    method public void close();
    method public void copyStringToBuffer(int, int, android.database.CharArrayBuffer);
    method public int describeContents();
    method public void freeLastRow();
@@ -7236,13 +7235,14 @@ package android.database.sqlite {
    ctor public SQLiteCantOpenDatabaseException(java.lang.String);
  }
  public abstract class SQLiteClosable {
  public abstract class SQLiteClosable implements java.io.Closeable {
    ctor public SQLiteClosable();
    method public void acquireReference();
    method public void close();
    method protected abstract void onAllReferencesReleased();
    method protected void onAllReferencesReleasedFromContainer();
    method protected deprecated void onAllReferencesReleasedFromContainer();
    method public void releaseReference();
    method public void releaseReferenceFromContainer();
    method public deprecated void releaseReferenceFromContainer();
  }
  public class SQLiteConstraintException extends android.database.sqlite.SQLiteException {
@@ -7272,7 +7272,6 @@ package android.database.sqlite {
    method public void beginTransactionNonExclusive();
    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
    method public void close();
    method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
    method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
    method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
@@ -7415,7 +7414,6 @@ package android.database.sqlite {
    method public void bindNull(int);
    method public void bindString(int, java.lang.String);
    method public void clearBindings();
    method public void close();
    method public final deprecated int getUniqueId();
    method protected void onAllReferencesReleased();
  }
+3 −1
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.os.Bundle;

import java.io.Closeable;

/**
 * This interface provides random read-write access to the result set returned
 * by a database query.
@@ -27,7 +29,7 @@ import android.os.Bundle;
 * Cursor implementations are not required to be synchronized so code using a Cursor from multiple
 * threads should perform its own synchronization when using the Cursor.
 */
public interface Cursor {
public interface Cursor extends Closeable {
    /*
     * Values returned by {@link #getType(int)}.
     * These should be consistent with the corresponding types defined in CursorWindow.h
+7 −10
Original line number Diff line number Diff line
@@ -168,14 +168,6 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
        return mName;
    }

    /**
     * Closes the cursor window and frees its underlying resources when all other
     * remaining references have been released.
     */
    public void close() {
        releaseReference();
    }

    /**
     * Clears out the existing contents of the window, making it safe to reuse
     * for new data.
@@ -703,8 +695,13 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
    }

    public void writeToParcel(Parcel dest, int flags) {
        acquireReference();
        try {
            dest.writeInt(mStartPos);
            nativeWriteToParcel(mWindowPtr, dest);
        } finally {
            releaseReference();
        }

        if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
            releaseReference();
+45 −52
Original line number Diff line number Diff line
@@ -269,8 +269,6 @@ public class DatabaseUtils {
        if (position < 0 || position >= cursor.getCount()) {
            return;
        }
        window.acquireReference();
        try {
        final int oldPos = cursor.getPosition();
        final int numColumns = cursor.getColumnCount();
        window.clear();
@@ -321,11 +319,6 @@ public class DatabaseUtils {
            } while (cursor.moveToNext());
        }
        cursor.moveToPosition(oldPos);
        } catch (IllegalStateException e){
            // simply ignore it
        } finally {
            window.releaseReference();
        }
    }

    /**
+53 −2
Original line number Diff line number Diff line
@@ -16,15 +16,39 @@

package android.database.sqlite;

import java.io.Closeable;

/**
 * An object created from a SQLiteDatabase that can be closed.
 *
 * This class implements a primitive reference counting scheme for database objects.
 */
public abstract class SQLiteClosable {
public abstract class SQLiteClosable implements Closeable {
    private int mReferenceCount = 1;

    /**
     * Called when the last reference to the object was released by
     * a call to {@link #releaseReference()} or {@link #close()}.
     */
    protected abstract void onAllReferencesReleased();
    protected void onAllReferencesReleasedFromContainer() {}

    /**
     * Called when the last reference to the object was released by
     * a call to {@link #releaseReferenceFromContainer()}.
     *
     * @deprecated Do not use.
     */
    @Deprecated
    protected void onAllReferencesReleasedFromContainer() {
        onAllReferencesReleased();
    }

    /**
     * Acquires a reference to the object.
     *
     * @throws IllegalStateException if the last reference to the object has already
     * been released.
     */
    public void acquireReference() {
        synchronized(this) {
            if (mReferenceCount <= 0) {
@@ -35,6 +59,12 @@ public abstract class SQLiteClosable {
        }
    }

    /**
     * Releases a reference to the object, closing the object if the last reference
     * was released.
     *
     * @see #onAllReferencesReleased()
     */
    public void releaseReference() {
        boolean refCountIsZero = false;
        synchronized(this) {
@@ -45,6 +75,14 @@ public abstract class SQLiteClosable {
        }
    }

    /**
     * Releases a reference to the object that was owned by the container of the object,
     * closing the object if the last reference was released.
     *
     * @see #onAllReferencesReleasedFromContainer()
     * @deprecated Do not use.
     */
    @Deprecated
    public void releaseReferenceFromContainer() {
        boolean refCountIsZero = false;
        synchronized(this) {
@@ -54,4 +92,17 @@ public abstract class SQLiteClosable {
            onAllReferencesReleasedFromContainer();
        }
    }

    /**
     * Releases a reference to the object, closing the object if the last reference
     * was released.
     *
     * Calling this method is equivalent to calling {@link #releaseReference}.
     *
     * @see #releaseReference()
     * @see #onAllReferencesReleased()
     */
    public void close() {
        releaseReference();
    }
}
Loading